Skip to content

Commit 6c32b19

Browse files
committed
feat: ability to parse transaction data using block.tlb to get additional data
1 parent 6e06f4e commit 6c32b19

File tree

13 files changed

+569
-0
lines changed

13 files changed

+569
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,5 @@ The number of additional dependencies you need depends of what you already have
8989

9090
* TON ADNL API Home: https://ton.org/docs/develop/dapps/apis/adnl
9191
* TonLib TL Schema: https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl
92+
* Block.tlb schema: https://github.com/ton-blockchain/ton/blob/master/crypto/block/block.tlb
9293
* TL Language description: https://core.telegram.org/mtproto/TL
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using TonLibDotNet.Cells;
2+
3+
namespace TonLibDotNet.BlocksTlb
4+
{
5+
public class TransactionTests
6+
{
7+
/*
8+
* Transaction https://tonscan.org/tx/8DW9F1LSXj62Etlu9XC5Lf5hT0n%2F2a9aPYQOHxWkW9w=
9+
* same as https://tonviewer.com/transaction/f035bd1752d25e3eb612d96ef570b92dfe614f49ffd9af5a3d840e1f15a45bdc
10+
* same as https://explorer.toncoin.org/transaction?account=0:83dfd552e63729b472fcbcc8c45ebcc6691702558b68ec7527e1ba403a0f31a8&lt=44333298000001&hash=f035bd1752d25e3eb612d96ef570b92dfe614f49ffd9af5a3d840e1f15a45bdc
11+
*/
12+
const string DataBase64 = @"te6cckECBwEAAUoAA7F4Pf1VLmNym0cvy8yMRevMZpFwJVi2jsdSfhukA6DzGoAAAoUiZ6oIEv
13+
I+ZP+csu5b/Ww2AH3IyZraBX+XRMwdA4+SfIPFgNdgAAKFIX/r3BZbqkgwABQmKAECAwEBoAQAgnKPZ4CIWhhMygQJE3Wmow8XqXr4BABWnZ3b
14+
b88QOnKWAZDgk9ogaasitJqaQ86vh2+QyzkjPZExXG+5Y6krzj7YAAsMTEhASSABq0gAbKlIy4tYiy0htZWJsr9rQB+v4FdFbNVrBLh6ZEsPUc
15+
UAIPf1VLmNym0cvy8yMRevMZpFwJVi2jsdSfhukA6DzGoEBAYihpwAAFCkTJmzhMt1SOzABQFtc2LQnAAAAY1hEf9OgBY0V4XYoAAIANQF40Uz
16+
/r/7eXN0fHrQfDFksLTrZDXRZ0b5b9I25iw1wAYAEAAAAADwn6auad9mOw==";
17+
18+
[Fact]
19+
public void ParseTest()
20+
{
21+
var slice = Boc.ParseFromBase64(DataBase64).RootCells[0].BeginRead();
22+
var tx = new BlocksTlb.Transaction(slice);
23+
24+
Assert.NotNull(tx);
25+
26+
Assert.Equal("83DFD552E63729B472FCBCC8C45EBCC6691702558B68EC7527E1BA403A0F31A8", Convert.ToHexString(tx.AccountAddr));
27+
Assert.Equal((ulong)44333298000001, tx.Lt);
28+
Assert.Equal("2F23E64FF9CB2EE5BFD6C36007DC8C99ADA057F9744CC1D038F927C83C580D76", Convert.ToHexString(tx.PrevTransHash));
29+
Assert.Equal((ulong)44333055000001, tx.PrevTransLt);
30+
Assert.Equal((uint)1706730627, tx.Now);
31+
Assert.Equal((ulong)0, tx.OutmsgCnt);
32+
Assert.True(tx.OriginalStatus.IsActive);
33+
Assert.True(tx.EndStatus.IsActive);
34+
35+
var d = tx.Description as TransactionDescr.Ord;
36+
Assert.NotNull(d);
37+
38+
Assert.True(d.CreditFirst);
39+
40+
Assert.NotNull(d.StoragePh);
41+
Assert.Equal(49, d.StoragePh.StorageFeesCollected);
42+
Assert.Equal(0, d.StoragePh.StorageFeesDue);
43+
Assert.True(d.StoragePh.StatusChange.IsUnchanged);
44+
45+
Assert.NotNull(d.CreditPh);
46+
Assert.Equal(0, d.CreditPh.DueFeesCollected);
47+
Assert.NotNull(d.CreditPh.Credit);
48+
Assert.Equal(1, d.CreditPh.Credit.Grams);
49+
50+
Assert.NotNull(d.ComputePh);
51+
Assert.True(d.ComputePh.IsSkipped);
52+
Assert.True(((TrComputePhase.Skipped)d.ComputePh).Reason.IsNoGas);
53+
54+
Assert.Null(d.Action);
55+
56+
Assert.True(d.Aborted);
57+
}
58+
}
59+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using TonLibDotNet.Cells;
2+
3+
namespace TonLibDotNet.BlocksTlb
4+
{
5+
/// <remarks>
6+
/// <code>
7+
/// acst_unchanged$0 = AccStatusChange; // x -> x
8+
/// acst_frozen$10 = AccStatusChange; // init -> frozen
9+
/// acst_deleted$11 = AccStatusChange; // frozen -> deleted
10+
/// </code></remarks>
11+
public abstract class AccStatusChange
12+
{
13+
public virtual bool IsUnchanged { get; } = false;
14+
15+
public virtual bool IsFrozen { get; } = false;
16+
17+
public virtual bool IsDeleted { get; } = false;
18+
19+
public static AccStatusChange CreateFrom(Slice src)
20+
{
21+
if (src.LoadBit())
22+
{
23+
return src.LoadBit() ? Deleted.Instance : Frozen.Instance;
24+
}
25+
else
26+
{
27+
return Unchanged.Instance;
28+
}
29+
}
30+
31+
public class Unchanged : AccStatusChange
32+
{
33+
public static readonly Unchanged Instance = new();
34+
35+
public override bool IsUnchanged => true;
36+
}
37+
38+
public class Frozen: AccStatusChange
39+
{
40+
public static readonly Frozen Instance = new();
41+
42+
public override bool IsFrozen => true;
43+
}
44+
45+
public class Deleted : AccStatusChange
46+
{
47+
public static readonly Deleted Instance = new();
48+
49+
public override bool IsDeleted => true;
50+
}
51+
}
52+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using TonLibDotNet.Cells;
2+
3+
namespace TonLibDotNet.BlocksTlb
4+
{
5+
/// <remarks>
6+
/// <code>
7+
/// acc_state_uninit$00 = AccountStatus;
8+
/// acc_state_frozen$01 = AccountStatus;
9+
/// acc_state_active$10 = AccountStatus;
10+
/// acc_state_nonexist$11 = AccountStatus;
11+
/// </code></remarks>
12+
public abstract class AccountStatus
13+
{
14+
public virtual bool IsUninit { get; } = false;
15+
16+
public virtual bool IsFrozen { get; } = false;
17+
18+
public virtual bool IsActive { get; } = false;
19+
20+
public virtual bool IsNonexist { get; } = false;
21+
22+
public static AccountStatus CreateFrom(Slice src)
23+
{
24+
return src.LoadUInt(2) switch
25+
{
26+
0 => Uninit.Instance,
27+
1 => Frozen.Instance,
28+
2 => Active.Instance,
29+
3 => Nonexist.Instance,
30+
_ => throw new InvalidOperationException(), // Can't get here because 2 bits are always between 0 and 3.
31+
};
32+
}
33+
34+
public class Uninit : AccountStatus
35+
{
36+
public static readonly Uninit Instance = new();
37+
38+
public override bool IsUninit => true;
39+
}
40+
41+
public class Frozen : AccountStatus
42+
{
43+
public static readonly Frozen Instance = new();
44+
45+
public override bool IsFrozen => true;
46+
}
47+
48+
public class Active : AccountStatus
49+
{
50+
public static readonly Active Instance = new();
51+
52+
public override bool IsActive => true;
53+
}
54+
55+
public class Nonexist : AccountStatus
56+
{
57+
public static readonly Nonexist Instance = new();
58+
59+
public override bool IsNonexist => true;
60+
}
61+
}
62+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using TonLibDotNet.Cells;
2+
3+
namespace TonLibDotNet.BlocksTlb
4+
{
5+
/// <remarks><code>
6+
/// cskip_no_state$00 = ComputeSkipReason;
7+
/// cskip_bad_state$01 = ComputeSkipReason;
8+
/// cskip_no_gas$10 = ComputeSkipReason;
9+
/// cskip_suspended$110 = ComputeSkipReason;
10+
/// </code></remarks>
11+
public abstract class ComputeSkipReason
12+
{
13+
public virtual bool IsNoState { get; } = false;
14+
15+
public virtual bool IsBadState { get; } = false;
16+
17+
public virtual bool IsNoGas { get; } = false;
18+
19+
public virtual bool IsSuspended { get; } = false;
20+
21+
public static ComputeSkipReason CreateFrom(Slice src)
22+
{
23+
if (src.LoadBit())
24+
{
25+
if (src.LoadBit())
26+
{
27+
if (!src.LoadBit())
28+
{
29+
return Suspended.Instance;
30+
}
31+
else
32+
{
33+
throw new InvalidOperationException("Failed to load: unexpected bit value");
34+
}
35+
}
36+
else
37+
{
38+
return NoGas.Instance;
39+
}
40+
}
41+
else
42+
{
43+
return src.LoadBit() ? BadState.Instance : NoState.Instance;
44+
}
45+
}
46+
47+
public class NoState : ComputeSkipReason
48+
{
49+
public static readonly NoState Instance = new();
50+
51+
public override bool IsNoState => true;
52+
}
53+
54+
public class BadState : ComputeSkipReason
55+
{
56+
public static readonly BadState Instance = new();
57+
58+
public override bool IsBadState => true;
59+
}
60+
61+
public class NoGas : ComputeSkipReason
62+
{
63+
public static readonly NoGas Instance = new();
64+
65+
public override bool IsNoGas => true;
66+
}
67+
68+
public class Suspended : ComputeSkipReason
69+
{
70+
public static readonly Suspended Instance = new();
71+
72+
public override bool IsSuspended => true;
73+
}
74+
}
75+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using TonLibDotNet.Cells;
2+
3+
namespace TonLibDotNet.BlocksTlb
4+
{
5+
/// <remarks><code>
6+
/// currencies$_ grams:Grams other:ExtraCurrencyCollection = CurrencyCollection
7+
/// </code></remarks>
8+
public class CurrencyCollection
9+
{
10+
public CurrencyCollection(Slice src)
11+
{
12+
Grams = src.LoadCoins();
13+
Other = new ExtraCurrencyCollection(src);
14+
}
15+
16+
public long Grams { get; set; }
17+
18+
public ExtraCurrencyCollection Other { get; set; }
19+
}
20+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using TonLibDotNet.Cells;
2+
3+
namespace TonLibDotNet.BlocksTlb
4+
{
5+
/// <remarks><code>
6+
/// extra_currencies$_ dict:(HashmapE 32 (VarUInteger 32)) = ExtraCurrencyCollection;
7+
/// </code></remarks>
8+
public class ExtraCurrencyCollection
9+
{
10+
public ExtraCurrencyCollection(Slice src)
11+
{
12+
Dict = src.TryLoadDict();
13+
}
14+
15+
public Cell? Dict { get; set; }
16+
}
17+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using TonLibDotNet.Cells;
2+
3+
namespace TonLibDotNet.BlocksTlb
4+
{
5+
/// <summary>
6+
///
7+
/// </summary>
8+
/// <remarks><code>
9+
/// tr_phase_compute_skipped$0 reason:ComputeSkipReason = TrComputePhase;
10+
///
11+
/// tr_phase_compute_vm$1 success:Bool msg_state_used:Bool
12+
/// account_activated:Bool gas_fees:Grams
13+
/// ^[gas_used:(VarUInteger 7)
14+
/// gas_limit:(VarUInteger 7) gas_credit:(Maybe(VarUInteger 3))
15+
/// mode:int8 exit_code:int32 exit_arg:(Maybe int32)
16+
/// vm_steps:uint32
17+
/// vm_init_state_hash:bits256 vm_final_state_hash:bits256]
18+
/// = TrComputePhase;
19+
/// </code></remarks>
20+
public abstract class TrComputePhase
21+
{
22+
public virtual bool IsSkipped { get; } = false;
23+
24+
public virtual bool IsVm { get; } = false;
25+
26+
public static TrComputePhase CreateFrom(Slice src)
27+
{
28+
return src.LoadBit() ? new Vm(src) : new Skipped(src);
29+
}
30+
31+
public class Skipped : TrComputePhase
32+
{
33+
public Skipped(Slice src)
34+
{
35+
Reason = ComputeSkipReason.CreateFrom(src);
36+
}
37+
38+
public override bool IsSkipped => true;
39+
40+
public ComputeSkipReason Reason { get; set; }
41+
}
42+
43+
public class Vm : TrComputePhase
44+
{
45+
public Vm(Slice src)
46+
{
47+
Success = src.LoadBit();
48+
MsgStateUsed = src.LoadBit();
49+
AccountActivated = src.LoadBit();
50+
GasFees = src.LoadCoins();
51+
GasUsed = src.LoadRef();
52+
}
53+
54+
public override bool IsVm => true;
55+
56+
public bool Success { get; set; }
57+
58+
public bool MsgStateUsed { get; set; }
59+
60+
public bool AccountActivated { get; set; }
61+
62+
public long GasFees { get; set; }
63+
64+
public Cell GasUsed { get; set; }
65+
}
66+
}
67+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using TonLibDotNet.Cells;
2+
3+
namespace TonLibDotNet.BlocksTlb
4+
{
5+
/// <remarks><code>
6+
/// tr_phase_credit$_ due_fees_collected:(Maybe Grams) credit:CurrencyCollection = TrCreditPhase;
7+
/// </code></remarks>
8+
public class TrCreditPhase
9+
{
10+
public TrCreditPhase(Slice src)
11+
{
12+
if (src.LoadBit())
13+
{
14+
DueFeesCollected = src.LoadCoins();
15+
}
16+
17+
Credit = new CurrencyCollection(src);
18+
}
19+
20+
public long DueFeesCollected { get; set; }
21+
22+
public CurrencyCollection Credit { get; set; }
23+
}
24+
}

0 commit comments

Comments
 (0)