diff --git a/cell/src/main/java/org/ton/java/tlb/types/OutList.java b/cell/src/main/java/org/ton/java/tlb/types/OutList.java index 9b2ca197..cd808bc7 100644 --- a/cell/src/main/java/org/ton/java/tlb/types/OutList.java +++ b/cell/src/main/java/org/ton/java/tlb/types/OutList.java @@ -27,7 +27,10 @@ public Cell toCell() { int i = 0; for (OutAction action : actions) { Cell outMsg = action.toCell(); - list = CellBuilder.beginCell().storeRef(list).storeCell(outMsg).endCell(); + list = CellBuilder.beginCell() + .storeRef(list) + .storeCell(outMsg) + .endCell(); } return list; } diff --git a/cell/src/main/java/org/ton/java/tlb/types/VmStackValueTuple.java b/cell/src/main/java/org/ton/java/tlb/types/VmStackValueTuple.java index c021c975..738da0c9 100644 --- a/cell/src/main/java/org/ton/java/tlb/types/VmStackValueTuple.java +++ b/cell/src/main/java/org/ton/java/tlb/types/VmStackValueTuple.java @@ -24,16 +24,18 @@ public class VmStackValueTuple implements VmStackValue { public Cell toCell() { return CellBuilder.beginCell() .storeUint(0x07, 8) - .storeUint(len, 16) + .storeUint(data.getValues().size(), 16) .storeCell(data.toCell()) .endCell(); } public static VmStackValueTuple deserialize(CellSlice cs) { + int magic = cs.loadUint(8).intValue(); + int len = cs.loadUint(16).intValue(); return VmStackValueTuple.builder() - .magic(cs.loadUint(8).intValue()) - .len(cs.loadUint(16).intValue()) - .data(VmTuple.deserialize(cs)) + .magic(magic) + .len(len) + .data(VmTuple.deserialize(cs, len)) .build(); } } diff --git a/cell/src/main/java/org/ton/java/tlb/types/VmTuple.java b/cell/src/main/java/org/ton/java/tlb/types/VmTuple.java index f4a2d38c..2c5109f5 100644 --- a/cell/src/main/java/org/ton/java/tlb/types/VmTuple.java +++ b/cell/src/main/java/org/ton/java/tlb/types/VmTuple.java @@ -8,7 +8,11 @@ import org.ton.java.cell.CellBuilder; import org.ton.java.cell.CellSlice; +import java.util.ArrayList; +import java.util.List; + /** + * vm_tuple_nil$_ = VmTuple 0; * vm_tuple_tcons$_ {n:#} head:(VmTupleRef n) tail:^VmStackValue = VmTuple (n + 1); */ @Builder @@ -16,20 +20,48 @@ @Setter @ToString public class VmTuple { - VmTupleRef head; - VmStackValue tail; + List values; public Cell toCell() { + List pValues = new ArrayList<>(values); + if (pValues.size() == 0) { + return CellBuilder.beginCell().endCell(); + } + + VmStackValue v = pValues.get(pValues.size() - 1); + pValues.remove(pValues.size() - 1); + return CellBuilder.beginCell() + .storeCell(VmTupleRef.toCell(pValues)) + .storeRef(v.toCell()) + .endCell(); + } + + public static Cell toCell(List pValues) { + List lValues = new ArrayList<>(pValues); + + if (lValues.size() == 0) { + return CellBuilder.beginCell().endCell(); + } + + VmStackValue v = lValues.get(lValues.size() - 1); + lValues.remove(lValues.size() - 1); return CellBuilder.beginCell() - .storeCell(head.toCell()) - .storeRef(tail.toCell()) + .storeCell(VmTupleRef.toCell(lValues)) + .storeRef(v.toCell()) .endCell(); } - public static VmTuple deserialize(CellSlice cs) { + public static VmTuple deserialize(CellSlice cs, int len) { + if (len == 0) { + return VmTuple.builder().build(); + } + + ArrayList ar = new ArrayList<>(); + ar.add((VmStackValue) VmTupleRef.deserialize(cs, len - 1)); + ar.add(cs.getRefsCount() > 0 ? VmStackValue.deserialize(CellSlice.beginParse(cs.loadRef())) : null); + return VmTuple.builder() - .head(VmTupleRef.deserialize(cs)) - .tail(cs.getRefsCount() > 0 ? VmStackValue.deserialize(CellSlice.beginParse(cs.loadRef())) : null) + .values(ar) .build(); } } diff --git a/cell/src/main/java/org/ton/java/tlb/types/VmTupleRef.java b/cell/src/main/java/org/ton/java/tlb/types/VmTupleRef.java index 59ce6104..f62443a8 100644 --- a/cell/src/main/java/org/ton/java/tlb/types/VmTupleRef.java +++ b/cell/src/main/java/org/ton/java/tlb/types/VmTupleRef.java @@ -8,6 +8,9 @@ import org.ton.java.cell.CellBuilder; import org.ton.java.cell.CellSlice; +import java.util.Collections; +import java.util.List; + /** * vm_tupref_nil$_ = VmTupleRef 0; * vm_tupref_single$_ entry:^VmStackValue = VmTupleRef 1; @@ -17,26 +20,53 @@ @Getter @Setter @ToString -public class VmTupleRef { - VmStackValue entry; +public class VmTupleRef implements VmStackValue { + List values; + + @Override public Cell toCell() { + throw new Error("wrong usage"); + } + + public Cell toCell(int len) { + if (len == 0) { + return CellBuilder.beginCell().endCell(); + } + if (len == 1) { + return CellBuilder.beginCell() + .storeRef(((VmStackValue) values.get(0)).toCell()) + .endCell(); + } return CellBuilder.beginCell() - .storeRef(entry.toCell()) + .storeRef(VmTuple.toCell(values)) .endCell(); } - public static VmTupleRef deserialize(CellSlice cs) { // more tests are required + public static Cell toCell(List pValues) { + if (pValues.size() == 0) { + return CellBuilder.beginCell().endCell(); + } + if (pValues.size() == 1) { + return CellBuilder.beginCell() + .storeRef(((VmStackValue) pValues.get(0)).toCell()) + .endCell(); + } + return CellBuilder.beginCell() + .storeRef(VmTuple.toCell(pValues)) + .endCell(); + } + + public static VmTuple deserialize(CellSlice cs, int len) { // more tests are required if (cs.getRefsCount() == 0) { - return null; + return VmTuple.builder().build(); } else if (cs.getRefsCount() == 1) { - return VmTupleRef.builder() - .entry(VmStackValue.deserialize(cs)) - .build(); - } else { - return VmTupleRef.builder() - .entry(VmStackValue.deserialize(CellSlice.beginParse(cs.loadRef()))) + return VmTuple.builder() + .values(Collections.singletonList(VmStackValue.deserialize(CellSlice.beginParse(cs.loadRef())))) .build(); } + + return VmTuple.deserialize(CellSlice.beginParse(cs.loadRef()), len); + } } diff --git a/emulator/src/test/java/org/ton/java/emulator/TestTvmEmulator.java b/emulator/src/test/java/org/ton/java/emulator/TestTvmEmulator.java index 7b6f01b5..28837bd5 100644 --- a/emulator/src/test/java/org/ton/java/emulator/TestTvmEmulator.java +++ b/emulator/src/test/java/org/ton/java/emulator/TestTvmEmulator.java @@ -22,6 +22,7 @@ import org.ton.java.smartcontract.wallet.v4.WalletV4R2; import org.ton.java.tlb.types.*; import org.ton.java.tonlib.Tonlib; +import org.ton.java.tonlib.types.BlockIdExt; import org.ton.java.tonlib.types.SmcLibraryEntry; import org.ton.java.tonlib.types.SmcLibraryResult; import org.ton.java.utils.Utils; @@ -29,6 +30,7 @@ import java.io.IOException; import java.math.BigInteger; import java.time.Instant; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.concurrent.ExecutionException; @@ -490,17 +492,26 @@ public void testTvmEmulatorSendInternalMessage() { @Test public void testTvmEmulatorSetPrevBlockInfo() { - String infoBocBase64 = ""; - // must be tuple, below won't work -// BlkPrevInfo blkPrevInfo = BlkPrevInfo.builder() -// .prev1(ExtBlkRef.builder() -// .seqno(10) -// .endLt(BigInteger.valueOf(500000000)) -// .fileHash(BigInteger.ONE) -// .rootHash(BigInteger.TEN) -// .build()) -// .build(); - assertTrue(tvmEmulator.setPrevBlockInfo(infoBocBase64)); + BlockIdExt lastBlock = tonlib.getLast().getLast(); + log.info("lastBlockId: {}", lastBlock); + + ArrayList stack = new ArrayList<>(); + stack.add(VmStackValueTinyInt.builder().value(BigInteger.valueOf(lastBlock.getWorkchain())).build()); + stack.add(VmStackValueTinyInt.builder().value(BigInteger.valueOf(lastBlock.getShard())).build()); + stack.add(VmStackValueTinyInt.builder().value(BigInteger.valueOf(lastBlock.getSeqno())).build()); + stack.add(VmStackValueInt.builder().value(new BigInteger(Utils.base64ToHexString(lastBlock.getRoot_hash()), 16)).build()); + stack.add(VmStackValueInt.builder().value(new BigInteger(Utils.base64ToHexString(lastBlock.getFile_hash()), 16)).build()); + + VmStackValueTuple vmStackValueTuple = VmStackValueTuple.builder() + .data(VmTuple.builder() + .values(stack) + .build()) + .build(); + + Cell deserializedTuple = CellBuilder.beginCell().fromBocBase64(vmStackValueTuple.toCell().toBase64()).endCell(); + log.info("test deserialization: {}", deserializedTuple); + + assertTrue(tvmEmulator.setPrevBlockInfo(vmStackValueTuple.toCell().toBase64())); }