Skip to content

Commit

Permalink
improved TransactionDescription handling; add simplified calculation …
Browse files Browse the repository at this point in the history
…of tx fees; added EmulateTransactionResult -> printTransactionFees()
  • Loading branch information
neodix42 committed Oct 14, 2024
1 parent e72375b commit a215e1c
Show file tree
Hide file tree
Showing 19 changed files with 1,052 additions and 339 deletions.
7 changes: 3 additions & 4 deletions cell/src/main/java/org/ton/java/tlb/types/ActionPhase.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package org.ton.java.tlb.types;

import java.math.BigInteger;
import lombok.Builder;
import lombok.Data;
import org.ton.java.cell.Cell;
import org.ton.java.cell.CellBuilder;
import org.ton.java.cell.CellSlice;

import java.math.BigInteger;

/**
* <pre>
* tr_phase_action$_
Expand Down Expand Up @@ -75,8 +74,8 @@ public static ActionPhase deserialize(CellSlice cs) {
.valid(cs.loadBit())
.noFunds(cs.loadBit())
.statusChange(AccStatusChange.deserialize(cs))
.totalFwdFees(cs.loadBit() ? cs.loadCoins() : null)
.totalActionFees(cs.loadBit() ? cs.loadCoins() : null)
.totalFwdFees(cs.loadBit() ? cs.loadCoins() : BigInteger.ZERO)
.totalActionFees(cs.loadBit() ? cs.loadCoins() : BigInteger.ZERO)
.resultCode(cs.loadUint(32).longValue())
.resultArg(cs.loadBit() ? cs.loadUint(32).longValue() : 0)
.totalActions(cs.loadUint(16).longValue())
Expand Down
6 changes: 0 additions & 6 deletions cell/src/main/java/org/ton/java/tlb/types/CommonMsg.java

This file was deleted.

188 changes: 188 additions & 0 deletions cell/src/main/java/org/ton/java/tlb/types/Transaction.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.ton.java.tlb.types;

import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;

import java.math.BigInteger;
Expand All @@ -9,6 +10,7 @@
import org.ton.java.cell.CellBuilder;
import org.ton.java.cell.CellSlice;
import org.ton.java.cell.TonHashMapE;
import org.ton.java.utils.Utils;

/**
*
Expand Down Expand Up @@ -179,4 +181,190 @@ public static AccountStates deserializeAccountState(byte state) {
}
return null;
}

public TransactionFees getTransactionFees() {
Transaction tx = this;

BigInteger totalFees = tx.getTotalFees().getCoins();
BigInteger totalForwardFees = getForwardFees(tx.getDescription());
BigInteger computeFees = getComputeFees(tx.getDescription());

BigInteger inForwardFees = BigInteger.ZERO;
BigInteger valueIn = BigInteger.ZERO;
BigInteger valueOut = BigInteger.ZERO;
BigInteger op = null;
long exitCode = getExitCode(tx.getDescription());
long actionCode = getActionCode(tx.getDescription());
long totalActions = getTotalActions(tx.getDescription());

Message inMsg = tx.getInOut().getIn();
Cell body = inMsg.getBody();

if (nonNull(body) && body.getBits().getUsedBits() >= 32) {
op = CellSlice.beginParse(body).preloadInt(32);
} else {
op = BigInteger.ONE.negate();
}

if (inMsg.getInfo() instanceof InternalMessageInfo) {
valueIn = ((InternalMessageInfo) inMsg.getInfo()).getValue().getCoins();
inForwardFees = ((InternalMessageInfo) inMsg.getInfo()).getFwdFee();
}

for (Message outMsg : tx.getInOut().getOutMessages()) {
InternalMessageInfo intMsgInfo = (InternalMessageInfo) outMsg.getInfo();
valueOut = valueOut.add(intMsgInfo.getValue().getCoins());
}

return TransactionFees.builder()
.op(
(isNull(op))
? "N/A"
: (op.compareTo(BigInteger.ONE.negate()) != 0) ? op.toString(16) : "no body")
.valueIn(valueIn)
.valueOut(valueOut)
.totalFees(totalFees)
.outForwardFee(totalForwardFees)
.computeFee(computeFees)
.inForwardFee(inForwardFees)
.exitCode(exitCode)
.actionCode(actionCode)
.totalActions(totalActions)
.build();
}

private BigInteger getComputeFees(TransactionDescription txDesc) {
if (txDesc instanceof TransactionDescriptionOrdinary) {
ComputePhase computePhase = ((TransactionDescriptionOrdinary) txDesc).getComputePhase();
if (computePhase instanceof ComputePhaseVM) {
return ((ComputePhaseVM) computePhase).getGasFees();
}
} else if (txDesc instanceof TransactionDescriptionSplitPrepare) {
ComputePhase computePhase = ((TransactionDescriptionSplitPrepare) txDesc).getComputePhase();
if (computePhase instanceof ComputePhaseVM) {
return ((ComputePhaseVM) computePhase).getGasFees();
}
} else if (txDesc instanceof TransactionDescriptionTickTock) {
ComputePhase computePhase = ((TransactionDescriptionTickTock) txDesc).getComputePhase();
if (computePhase instanceof ComputePhaseVM) {
return ((ComputePhaseVM) computePhase).getGasFees();
}
} else if (txDesc instanceof TransactionDescriptionMergeInstall) {
ComputePhase computePhase = ((TransactionDescriptionMergeInstall) txDesc).getComputePhase();
if (computePhase instanceof ComputePhaseVM) {
return ((ComputePhaseVM) computePhase).getGasFees();
}
} else {
return BigInteger.ZERO;
}
return BigInteger.ZERO;
}

private BigInteger getForwardFees(TransactionDescription txDesc) {
if (txDesc instanceof TransactionDescriptionOrdinary) {
ActionPhase actionPhase = ((TransactionDescriptionOrdinary) txDesc).getActionPhase();
return actionPhase.getTotalFwdFees();
} else if (txDesc instanceof TransactionDescriptionSplitPrepare) {
ActionPhase actionPhase = ((TransactionDescriptionSplitPrepare) txDesc).getActionPhase();
return actionPhase.getTotalFwdFees();
} else if (txDesc instanceof TransactionDescriptionTickTock) {
ActionPhase actionPhase = ((TransactionDescriptionTickTock) txDesc).getActionPhase();
return actionPhase.getTotalFwdFees();
} else if (txDesc instanceof TransactionDescriptionMergeInstall) {
ActionPhase actionPhase = ((TransactionDescriptionMergeInstall) txDesc).getActionPhase();
return actionPhase.getTotalFwdFees();
} else {
return BigInteger.ZERO;
}
}

private long getTotalActions(TransactionDescription txDesc) {
if (txDesc instanceof TransactionDescriptionOrdinary) {
ActionPhase actionPhase = ((TransactionDescriptionOrdinary) txDesc).getActionPhase();
return actionPhase.getTotalActions();
} else if (txDesc instanceof TransactionDescriptionSplitPrepare) {
ActionPhase actionPhase = ((TransactionDescriptionSplitPrepare) txDesc).getActionPhase();
return actionPhase.getTotalActions();
} else if (txDesc instanceof TransactionDescriptionTickTock) {
ActionPhase actionPhase = ((TransactionDescriptionTickTock) txDesc).getActionPhase();
return actionPhase.getTotalActions();
} else if (txDesc instanceof TransactionDescriptionMergeInstall) {
ActionPhase actionPhase = ((TransactionDescriptionMergeInstall) txDesc).getActionPhase();
return actionPhase.getTotalActions();
} else {
return -1;
}
}

private long getActionCode(TransactionDescription txDesc) {
if (txDesc instanceof TransactionDescriptionOrdinary) {
ActionPhase actionPhase = ((TransactionDescriptionOrdinary) txDesc).getActionPhase();
return actionPhase.getResultCode();
} else if (txDesc instanceof TransactionDescriptionSplitPrepare) {
ActionPhase actionPhase = ((TransactionDescriptionSplitPrepare) txDesc).getActionPhase();
return actionPhase.getResultCode();
} else if (txDesc instanceof TransactionDescriptionTickTock) {
ActionPhase actionPhase = ((TransactionDescriptionTickTock) txDesc).getActionPhase();
return actionPhase.getResultCode();
} else if (txDesc instanceof TransactionDescriptionMergeInstall) {
ActionPhase actionPhase = ((TransactionDescriptionMergeInstall) txDesc).getActionPhase();
return actionPhase.getResultCode();
} else {
return -1;
}
}

private long getExitCode(TransactionDescription txDesc) {
if (txDesc instanceof TransactionDescriptionOrdinary) {
ComputePhase computePhase = ((TransactionDescriptionOrdinary) txDesc).getComputePhase();
if (computePhase instanceof ComputePhaseVM) {
return ((ComputePhaseVM) computePhase).getDetails().getExitCode();
}
} else if (txDesc instanceof TransactionDescriptionSplitPrepare) {
ComputePhase computePhase = ((TransactionDescriptionSplitPrepare) txDesc).getComputePhase();
if (computePhase instanceof ComputePhaseVM) {
return ((ComputePhaseVM) computePhase).getDetails().getExitCode();
}
} else if (txDesc instanceof TransactionDescriptionTickTock) {
ComputePhase computePhase = ((TransactionDescriptionTickTock) txDesc).getComputePhase();
if (computePhase instanceof ComputePhaseVM) {
return ((ComputePhaseVM) computePhase).getDetails().getExitCode();
}
} else if (txDesc instanceof TransactionDescriptionMergeInstall) {
ComputePhase computePhase = ((TransactionDescriptionMergeInstall) txDesc).getComputePhase();
if (computePhase instanceof ComputePhaseVM) {
return ((ComputePhaseVM) computePhase).getDetails().getExitCode();
}
} else {
return -1;
}
return -1;
}

public void printTransactionFees(boolean withHeader) {
TransactionFees txFees = getTransactionFees();
String header =
"| op | valueIn | valueOut | totalFees | inForwardFee | outForwardFee | outActions | computeFee | exitCode | actionCode |";
if (withHeader) {
System.out.println(
"_________________________________________________________________________________________________________________________________________________");
System.out.println(header);
System.out.println(
"-------------------------------------------------------------------------------------------------------------------------------------------------");
}
String str =
String.format(
"| %-9s| %-15s| %-15s| %-13s| %-13s| %-14s| %-11s| %-14s| %-9s| %-11s|",
txFees.getOp(),
Utils.formatNanoValue(txFees.getValueIn()),
Utils.formatNanoValue(txFees.getValueOut()),
Utils.formatNanoValue(txFees.getTotalFees()),
Utils.formatNanoValue(txFees.getInForwardFee().toString()),
Utils.formatNanoValue(txFees.getOutForwardFee()),
txFees.getTotalActions(),
Utils.formatNanoValue(txFees.getComputeFee()),
txFees.getExitCode(),
txFees.getActionCode());
System.out.println(str);
}
}
147 changes: 94 additions & 53 deletions cell/src/main/java/org/ton/java/tlb/types/TransactionDescription.java
Original file line number Diff line number Diff line change
@@ -1,64 +1,105 @@
package org.ton.java.tlb.types;

import lombok.Builder;
import lombok.Data;
import org.ton.java.cell.Cell;
import org.ton.java.cell.CellBuilder;
import org.ton.java.cell.CellSlice;

@Builder
@Data
public class TransactionDescription {
Object description; // `tlb:"."`
/**
*
*
* <pre>
* trans_ord$0000 credit_first:Bool
* storage_ph:(Maybe TrStoragePhase)
* credit_ph:(Maybe TrCreditPhase)
* compute_ph:TrComputePhase action:(Maybe ^TrActionPhase)
* aborted:Bool bounce:(Maybe TrBouncePhase)
* destroyed:Bool
* = TransactionDescr;
*
* trans_storage$0001 storage_ph:TrStoragePhase
* = TransactionDescr;
*
* trans_tick_tock$001 is_tock:Bool storage_ph:TrStoragePhase
* compute_ph:TrComputePhase action:(Maybe ^TrActionPhase)
* aborted:Bool destroyed:Bool = TransactionDescr;
* //
* split_merge_info$_ cur_shard_pfx_len:(## 6)
* acc_split_depth:(## 6) this_addr:bits256 sibling_addr:bits256
* = SplitMergeInfo;
* trans_split_prepare$0100 split_info:SplitMergeInfo
* storage_ph:(Maybe TrStoragePhase)
* compute_ph:TrComputePhase action:(Maybe ^TrActionPhase)
* aborted:Bool destroyed:Bool
* = TransactionDescr;
* trans_split_install$0101 split_info:SplitMergeInfo
* prepare_transaction:^Transaction
* installed:Bool = TransactionDescr;
*
* trans_merge_prepare$0110 split_info:SplitMergeInfo
* storage_ph:TrStoragePhase aborted:Bool
* = TransactionDescr;
*
* trans_merge_install$0111 split_info:SplitMergeInfo
* prepare_transaction:^Transaction
* storage_ph:(Maybe TrStoragePhase)
* credit_ph:(Maybe TrCreditPhase)
* compute_ph:TrComputePhase action:(Maybe ^TrActionPhase)
* aborted:Bool destroyed:Bool
* = TransactionDescr;
* </pre>
*/
public interface TransactionDescription {

public Cell toCell() {
CellBuilder c = CellBuilder.beginCell();
Cell toCell();

if (description instanceof TransactionDescriptionStorage) {
c.storeUint(0b0001, 3);
c.storeSlice(CellSlice.beginParse(((TransactionDescriptionStorage) description).toCell()));
} else if (description instanceof TransactionDescriptionOrdinary) {
c.storeUint(0b000, 3);
c.storeSlice(CellSlice.beginParse(((TransactionDescriptionOrdinary) description).toCell()));
}
return c.endCell();
}
// {
// CellBuilder c = CellBuilder.beginCell();
//
// if (description instanceof TransactionDescriptionStorage) {
// c.storeUint(0b0001, 3);
// c.storeSlice(CellSlice.beginParse(((TransactionDescriptionStorage)
// description).toCell()));
// } else if (description instanceof TransactionDescriptionOrdinary) {
// c.storeUint(0b000, 3);
// c.storeSlice(CellSlice.beginParse(((TransactionDescriptionOrdinary)
// description).toCell()));
// }
// return c.endCell();
// }

public static TransactionDescription deserialize(CellSlice cs) {
int pfx = cs.preloadUint(3).intValue();
switch (pfx) {
case 0b000: {
boolean isStorage = cs.preloadBit();
if (isStorage) {
TransactionDescriptionStorage desc = TransactionDescriptionStorage.deserialize(cs);
return TransactionDescription.builder().description(desc).build();
}
TransactionDescriptionOrdinary descOrdinary = TransactionDescriptionOrdinary.deserialize(cs); // skipped was true
return TransactionDescription.builder().description(descOrdinary).build();
}
case 0b001: {
TransactionDescriptionTickTock descTickTock = TransactionDescriptionTickTock.deserialize(cs); // skipped was true
return TransactionDescription.builder().description(descTickTock).build();
}
case 0b010: {
boolean isInstall = cs.preloadBit();
if (isInstall) {
TransactionDescriptionSplitInstall descSplit = TransactionDescriptionSplitInstall.deserialize(cs); // skipped was true
return TransactionDescription.builder().description(descSplit).build();
}
TransactionDescriptionSplitPrepare descSplitPrepare = TransactionDescriptionSplitPrepare.deserialize(cs); // skipped was true
return TransactionDescription.builder().description(descSplitPrepare).build();
}
case 0b011: {
boolean isInstall = cs.preloadBit();
if (isInstall) {
TransactionDescriptionMergeInstall descMerge = TransactionDescriptionMergeInstall.deserialize(cs); // skipped was true
return TransactionDescription.builder().description(descMerge).build();
}
TransactionDescriptionMergePrepare descMergePrepare = TransactionDescriptionMergePrepare.deserialize(cs); // skipped was true
return TransactionDescription.builder().description(descMergePrepare).build();
}
static TransactionDescription deserialize(CellSlice cs) {
int pfx = cs.preloadUint(3).intValue();
switch (pfx) {
case 0b000:
{
boolean isStorage = cs.preloadBit();
if (isStorage) {
return TransactionDescriptionStorage.deserialize(cs);
}
return TransactionDescriptionOrdinary.deserialize(cs);
}
case 0b001:
{
return TransactionDescriptionTickTock.deserialize(cs);
}
case 0b010:
{
boolean isInstall = cs.preloadBit();
if (isInstall) {
return TransactionDescriptionSplitInstall.deserialize(cs);
}
return TransactionDescriptionSplitPrepare.deserialize(cs);
}
case 0b011:
{
boolean isInstall = cs.preloadBit();
if (isInstall) {
return TransactionDescriptionMergeInstall.deserialize(cs);
}
return TransactionDescriptionMergePrepare.deserialize(cs);
}
throw new Error("unknown transaction description type (must be in range [0..3], found 0x" + Integer.toBinaryString(pfx));
}
throw new Error(
"unknown transaction description type (must be in range [0..3], found 0x"
+ Integer.toBinaryString(pfx));
}
}
Loading

0 comments on commit a215e1c

Please sign in to comment.