From fa0c7f961ef8d30ff0021a6b51868e2740ad58bd Mon Sep 17 00:00:00 2001 From: Zakhar Petukhov Date: Fri, 2 Jun 2023 19:31:10 +0800 Subject: [PATCH 1/2] created method for parse raw and dns account, remove useless types --- account.go | 45 --------------- account/account_test.go | 32 +++++++++++ account/address.go | 115 +++++++++++++++++++++++++++++++++++++++ account/address_test.go | 65 ++++++++++++++++++++++ examples/liteapi/main.go | 5 +- liteapi/client_test.go | 6 +- tontest/helpers.go | 8 ++- txemulator/trace_test.go | 3 +- wallet/mock.go | 29 ++-------- wallet/wallet.go | 6 +- wallet/wallet_test.go | 8 ++- 11 files changed, 235 insertions(+), 87 deletions(-) create mode 100644 account/account_test.go create mode 100644 account/address.go create mode 100644 account/address_test.go diff --git a/account.go b/account.go index 2e35d836..0a4f9366 100644 --- a/account.go +++ b/account.go @@ -9,7 +9,6 @@ import ( "strings" "github.com/snksoft/crc" - "github.com/tonkeeper/tongo/tlb" "github.com/tonkeeper/tongo/utils" ) @@ -107,15 +106,6 @@ func (id *AccountID) ToMsgAddress() tlb.MsgAddress { } } -type AccountInfo struct { - Status tlb.AccountStatus - Balance uint64 - Data []byte - Code []byte - FrozenHash Bits256 - LastTransactionLt uint64 -} - func AccountIDFromBase64Url(s string) (AccountID, error) { var aa AccountID b, err := base64.URLEncoding.DecodeString(s) @@ -171,41 +161,6 @@ func MustParseAccountID(s string) AccountID { return aa } -func GetAccountInfo(a tlb.Account) (AccountInfo, error) { - if a.SumType == "AccountNone" { - return AccountInfo{Status: tlb.AccountNone}, nil - } - res := AccountInfo{ - Balance: uint64(a.Account.Storage.Balance.Grams), - LastTransactionLt: a.Account.Storage.LastTransLt, - } - if a.Account.Storage.State.SumType == "AccountUninit" { - res.Status = tlb.AccountUninit - return res, nil - } - if a.Account.Storage.State.SumType == "AccountFrozen" { - res.FrozenHash = Bits256(a.Account.Storage.State.AccountFrozen.StateHash) - res.Status = tlb.AccountFrozen - return res, nil - } - res.Status = tlb.AccountActive - if a.Account.Storage.State.AccountActive.StateInit.Data.Exists { - data, err := a.Account.Storage.State.AccountActive.StateInit.Data.Value.Value.ToBoc() - if err != nil { - return AccountInfo{}, err - } - res.Data = data - } - if a.Account.Storage.State.AccountActive.StateInit.Code.Exists { - code, err := a.Account.Storage.State.AccountActive.StateInit.Code.Value.Value.ToBoc() - if err != nil { - return AccountInfo{}, err - } - res.Code = code - } - return res, nil -} - // TODO: replace pointer with nullable type func AccountIDFromTlb(a tlb.MsgAddress) (*AccountID, error) { switch a.SumType { diff --git a/account/account_test.go b/account/account_test.go new file mode 100644 index 00000000..2655e645 --- /dev/null +++ b/account/account_test.go @@ -0,0 +1,32 @@ +package account + +import ( + "encoding/json" + "testing" +) + +func TestAccountIDJsonUnmarshal(t *testing.T) { + input := []byte(`{"A": "-1:7014a79eb7a81cf37542a62b75defa99427580e6612f956d47caa0fe0ec5d05e"}`) + var a struct { + A ID + } + err := json.Unmarshal(input, &a) + if err != nil { + t.Fatal(err) + } + if a.A.Workchain != -1 { + t.Fatal("invalid workchain") + } + for i, b := range []byte{112, 20, 167, 158, 183, 168, 28, 243, 117, 66, 166, 43, 117, 222, 250, 153, 66, 117, 128, 230, 97, 47, 149, 109, 71, 202, 160, 254, 14, 197, 208, 94} { + if a.A.Address[i] != b { + t.Fatal("invalid address") + } + } +} + +func TestToMsgAddress(t *testing.T) { + ma := (*ID)(nil).ToMsgAddress() + if ma.SumType != "AddrNone" { + t.Fatal(ma.SumType) + } +} diff --git a/account/address.go b/account/address.go new file mode 100644 index 00000000..f7808443 --- /dev/null +++ b/account/address.go @@ -0,0 +1,115 @@ +package account + +import ( + "context" + "encoding/base64" + "encoding/binary" + "fmt" + "strings" + "time" + + "github.com/snksoft/crc" + "github.com/tonkeeper/tongo" + "github.com/tonkeeper/tongo/contract/dns" + "github.com/tonkeeper/tongo/liteapi" + "github.com/tonkeeper/tongo/tlb" +) + +type executor interface { + RunSmcMethodByID(context.Context, ID, int, tlb.VmStack) (uint32, tlb.VmStack, error) +} + +type parser struct { + root tongo.AccountID + executor executor +} + +type ID = tongo.AccountID + +type Address struct { + ID + Bounce bool + StateInit *tlb.StateInit +} + +func (p *parser) Root(root ID) *parser { + p.root = root + return p +} + +func (p *parser) Executor(executor executor) *parser { + p.executor = executor + return p +} + +var DefaultParser *parser + +func init() { + DefaultParser = NewAccountParser() +} + +func Parser(a string) (Address, error) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + return DefaultParser.ParseAddress(ctx, a) +} + +func NewAccountParser() *parser { + defaultRoot := tongo.MustParseAccountID("-1:e56754f83426f69b09267bd876ac97c44821345b7e266bd956a7bfbfb98df35c") + return &parser{ + root: defaultRoot, + } +} + +func (p *parser) ParseAddress(ctx context.Context, address string) (Address, error) { + + accountID, err := tongo.AccountIDFromRaw(address) + if err == nil { + return Address{ID: accountID, Bounce: true, StateInit: nil}, nil + } + bytesAddress, _ := base64.URLEncoding.DecodeString(address) + if len(bytesAddress) == 36 { + checksum := uint64(binary.BigEndian.Uint16(bytesAddress[34:36])) + if checksum == crc.CalculateCRC(crc.XMODEM, bytesAddress[0:34]) { + bounce := bytesAddress[0]&0x11 == 0x11 + accountID.Workchain = int32(int8(bytesAddress[1])) + copy(accountID.Address[:], bytesAddress[2:34]) + return Address{ID: accountID, Bounce: bounce, StateInit: nil}, nil + } + } + if !strings.Contains(address, ".") { + return Address{}, fmt.Errorf("can't decode address %v", address) + } + if p.executor == nil { + var err error + p.executor, err = liteapi.NewClientWithDefaultMainnet() + if err != nil { + return Address{}, err + } + } + newDns := dns.NewDNS(p.root, p.executor) // import cycle in package/dns.go + result, err := newDns.Resolve(ctx, address) + if err != nil { + return Address{}, err + } + account := Address{Bounce: true} + for _, r := range result { + if r.SumType == "DNSSmcAddress" { + accountID, err := tongo.AccountIDFromTlb(r.DNSSmcAddress.Address) + if err != nil { + return Address{}, err + } + if accountID == nil { + return Address{}, fmt.Errorf("destination account is null") + } + account.ID = *accountID + for _, c := range r.DNSSmcAddress.SmcCapability.Interfaces { + if c == "wallet" { + account.Bounce = false + } + } + return account, nil + } + } + return Address{}, fmt.Errorf("address not found") +} diff --git a/account/address_test.go b/account/address_test.go new file mode 100644 index 00000000..d9e8e3e3 --- /dev/null +++ b/account/address_test.go @@ -0,0 +1,65 @@ +package account + +import ( + "context" + "testing" +) + +func TestParseAddress(t *testing.T) { + accountParser := NewAccountParser() + + const ( + parseToHumanAddress int = 1 + parseToRawAddress = 2 + parseDnsToRawAddress = 3 + ) + + type testCase struct { + name string + typeParse int + request string + response string + } + + for _, test := range []testCase{ + { + name: "Parse to raw address", + typeParse: parseToHumanAddress, + request: "0:91d73056e035232f09aaf8242a1d51eea98b6a5bebbf8ac0c9e521d02a1a4bdb", + response: "EQCR1zBW4DUjLwmq-CQqHVHuqYtqW-u_isDJ5SHQKhpL2wQV", + }, + { + name: "Parse to human address", + typeParse: parseToRawAddress, + request: "EQCR1zBW4DUjLwmq-CQqHVHuqYtqW-u_isDJ5SHQKhpL2wQV", + response: "0:91d73056e035232f09aaf8242a1d51eea98b6a5bebbf8ac0c9e521d02a1a4bdb", + }, + { + name: "Parse dns to raw address", + typeParse: parseDnsToRawAddress, + request: "blackpepper.ton", + response: "0:44556b55c15052eb44c6b75a9eccbc6280d32d598d12e975f435195795bb11d5", + }, + } { + t.Run(test.name, func(t *testing.T) { + account, err := accountParser.ParseAddress(context.Background(), test.request) + if err != nil { + t.Fatalf("failed parse %v address: %v", test.request, err) + } + switch test.typeParse { + case parseToHumanAddress: + if account.ID.ToHuman(true, false) != test.response { + t.Fatalf("not equal address") + } + case parseToRawAddress: + if account.ID.ToRaw() != test.response { + t.Fatalf("not equal address") + } + case parseDnsToRawAddress: + if account.ID.ToRaw() != test.response { + t.Fatalf("not equal address") + } + } + }) + } +} diff --git a/examples/liteapi/main.go b/examples/liteapi/main.go index 99de5c06..b12cb482 100644 --- a/examples/liteapi/main.go +++ b/examples/liteapi/main.go @@ -3,6 +3,7 @@ package main import ( "context" "fmt" + "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/liteapi" ) @@ -18,6 +19,6 @@ func main() { if err != nil { fmt.Printf("Get account state error: %v", err) } - acc, _ := tongo.GetAccountInfo(state.Account) - fmt.Printf("Account status: %v\nBalance: %v\n", acc.Status, acc.Balance) + + fmt.Printf("Account status: %v\nBalance: %v\n", state.Account.Status(), state.Account.Account.Storage.Balance.Grams) } diff --git a/liteapi/client_test.go b/liteapi/client_test.go index 9d5de5ce..191d2bd9 100644 --- a/liteapi/client_test.go +++ b/liteapi/client_test.go @@ -157,11 +157,7 @@ func TestGetAccountState(t *testing.T) { if err != nil { t.Fatal(err) } - ai, err := tongo.GetAccountInfo(st.Account) - if err != nil { - t.Fatal(err) - } - fmt.Printf("Account status: %v\n", ai.Status) + fmt.Printf("Account status: %v\n", st.Account.Status()) }) } } diff --git a/tontest/helpers.go b/tontest/helpers.go index 411bd3c9..1ac95e82 100644 --- a/tontest/helpers.go +++ b/tontest/helpers.go @@ -3,10 +3,11 @@ package tontest import ( "crypto/rand" "fmt" + "time" + "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" - "time" ) type accountBuilder struct { @@ -25,6 +26,11 @@ func Account() accountBuilder { return accountBuilder{} } +func (b accountBuilder) Address(a tongo.AccountID) accountBuilder { + b.address = &a + return b +} + func (b accountBuilder) Balance(grams tlb.Grams) accountBuilder { b.balance = &grams return b diff --git a/txemulator/trace_test.go b/txemulator/trace_test.go index 9c6f83e4..17269fb7 100644 --- a/txemulator/trace_test.go +++ b/txemulator/trace_test.go @@ -8,6 +8,7 @@ import ( "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/liteapi" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/tontest" "github.com/tonkeeper/tongo/wallet" ) @@ -26,7 +27,7 @@ func TestSimpleEmulation(t *testing.T) { w, err := wallet.DefaultWalletFromSeed(SEED, client) seqno := uint32(0) - mock, messages := wallet.NewMockBlockchain(seqno, tongo.AccountInfo{Status: "active"}) + mock, messages := wallet.NewMockBlockchain(seqno, tontest.Account().Address(tongo.AccountID{}).State(tlb.AccountActive).MustShardAccount()) w, err = wallet.DefaultWalletFromSeed(SEED, mock) if err != nil { t.Fatal(err) diff --git a/wallet/mock.go b/wallet/mock.go index 75fcef1b..fdeb4550 100644 --- a/wallet/mock.go +++ b/wallet/mock.go @@ -2,6 +2,7 @@ package wallet import ( "context" + "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/tlb" ) @@ -11,11 +12,11 @@ import ( // Only for internal tests and demonstration purposes. type SimpleMockBlockchain struct { seqno uint32 - state tongo.AccountInfo + state tlb.ShardAccount messages chan []byte } -func NewMockBlockchain(seqno uint32, state tongo.AccountInfo) (*SimpleMockBlockchain, chan []byte) { +func NewMockBlockchain(seqno uint32, state tlb.ShardAccount) (*SimpleMockBlockchain, chan []byte) { c := make(chan []byte, 100) return &SimpleMockBlockchain{ seqno: seqno, @@ -40,27 +41,5 @@ func (b *SimpleMockBlockchain) SendMessage(ctx context.Context, payload []byte) } func (b *SimpleMockBlockchain) GetAccountState(ctx context.Context, accountID tongo.AccountID) (tlb.ShardAccount, error) { - return tlb.ShardAccount{ - Account: tlb.Account{ - SumType: "Account", - Account: struct { - Addr tlb.MsgAddress - StorageStat tlb.StorageInfo - Storage tlb.AccountStorage - }{ - Addr: accountID.ToMsgAddress(), - Storage: tlb.AccountStorage{ - LastTransLt: 0, - Balance: tlb.CurrencyCollection{ - Grams: tlb.Grams(b.state.Balance), - }, - State: tlb.AccountState{ - SumType: "AccountActive", - }, - }, - }, - }, - LastTransHash: tlb.Bits256{}, - LastTransLt: 0, - }, nil + return b.state, nil } diff --git a/wallet/wallet.go b/wallet/wallet.go index e9ae4e5c..49b9c9c8 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -351,9 +351,5 @@ func (w *Wallet) GetBalance(ctx context.Context) (uint64, error) { if err != nil { return 0, err } - accInfo, err := tongo.GetAccountInfo(state.Account) - if err != nil { - return 0, err - } - return accInfo.Balance, nil + return uint64(state.Account.Account.Storage.Balance.Grams), nil } diff --git a/wallet/wallet_test.go b/wallet/wallet_test.go index 39c588df..8690ba6d 100644 --- a/wallet/wallet_test.go +++ b/wallet/wallet_test.go @@ -6,12 +6,14 @@ import ( "encoding/base64" "encoding/hex" "fmt" + "log" + "testing" + "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/liteapi" "github.com/tonkeeper/tongo/tlb" - "log" - "testing" + "github.com/tonkeeper/tongo/tontest" ) func TestGetCodeByVer(t *testing.T) { @@ -122,7 +124,7 @@ func TestGetSeqno(t *testing.T) { func TestMockBlockchain(t *testing.T) { recipientAddr, _ := tongo.AccountIDFromRaw("0:507dea7d606f22d9e85678d3eede39bbe133a868d2a0e3e07f5502cb70b8a512") - client, c := NewMockBlockchain(1, tongo.AccountInfo{Balance: 1000}) + client, c := NewMockBlockchain(1, tontest.Account().Balance(10000).Address(tongo.AccountID{}).MustShardAccount()) w := initDefaultWallet(client) tonTransfer := SimpleTransfer{ Amount: 10000, From 75733eee2244af2c7b2d45b4b86835fc47204745 Mon Sep 17 00:00:00 2001 From: "aleksej.paschenko" Date: Mon, 4 Sep 2023 15:53:53 +0300 Subject: [PATCH 2/2] Ton package to contains types from tongo's root package --- README.md | 2 +- abi/decoder_test.go | 4 +- abi/generated_test.go | 23 +- abi/generator.go | 4 +- abi/get_methods.go | 112 ++++----- abi/inspect.go | 8 +- abi/inspect_test.go | 4 +- abi/ordering.go | 4 +- abi/parser/generator.go | 8 +- abi/parser/invocation_order.tmpl | 2 +- account.go | 226 +++++++++--------- account/account_test.go | 32 --- account/address.go | 115 ---------- account/address_test.go => address_test.go | 18 +- bits.go | 123 +--------- block.go | 219 +----------------- cmd/func-compiler/main.go | 3 +- connect/v1.go | 1 + contract/dns/dns.go | 18 +- contract/dns/dns_test.go | 7 +- contract/jetton/jetton.go | 30 +-- contract/jetton/jetton_test.go | 13 +- contract/nft/nft.go | 20 +- examples/func-testing/example_test.go | 9 +- examples/jetton/main.go | 7 +- liteapi/client.go | 125 +++++----- liteapi/client_test.go | 54 ++--- liteapi/dns.go | 17 +- liteapi/jetton.go | 36 +-- liteapi/pool/connection.go | 12 +- liteapi/pool/failover_pool.go | 22 +- liteapi/pool/failover_pool_test.go | 8 +- liteapi/wallet.go | 5 +- liteclient/extensions.go | 17 +- liteclient/generated_test.go | 3 +- liteclient/keys.go | 1 + shards.go | 44 +--- tlb/benchmark_test.go | 2 +- ton/account.go | 173 ++++++++++++++ account_test.go => ton/account_test.go | 2 +- ton/address.go | 15 ++ ton/bits.go | 131 +++++++++++ bits_test.go => ton/bits_test.go | 2 +- ton/block.go | 240 ++++++++++++++++++++ block_test.go => ton/block_test.go | 2 +- grams.go => ton/grams.go | 2 +- ton/shards.go | 51 +++++ shards_test.go => ton/shards_test.go | 2 +- {testdata => ton/testdata}/raw-13516764.bin | Bin ton/transactions.go | 8 + tonconnect/server.go | 8 +- tontest/helpers.go | 20 +- transactions.go | 9 +- tvm/tvmExecutor.go | 6 +- tvm/tvmExecutor_test.go | 14 +- txemulator/trace.go | 22 +- txemulator/trace_test.go | 10 +- utils/generator.go | 3 +- wallet/mock.go | 6 +- wallet/models.go | 18 +- wallet/seed.go | 6 +- wallet/wallet.go | 55 ++--- wallet/wallet_test.go | 8 +- 63 files changed, 1149 insertions(+), 1022 deletions(-) delete mode 100644 account/account_test.go delete mode 100644 account/address.go rename account/address_test.go => address_test.go (78%) create mode 100644 ton/account.go rename account_test.go => ton/account_test.go (98%) create mode 100644 ton/address.go create mode 100644 ton/bits.go rename bits_test.go => ton/bits_test.go (97%) create mode 100644 ton/block.go rename block_test.go => ton/block_test.go (99%) rename grams.go => ton/grams.go (85%) create mode 100644 ton/shards.go rename shards_test.go => ton/shards_test.go (99%) rename {testdata => ton/testdata}/raw-13516764.bin (100%) create mode 100644 ton/transactions.go diff --git a/README.md b/README.md index 00ae79f2..0b43a225 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ go get github.com/tonkeeper/tongo ## Basic types Tongo operates with TON blockchain structures described in [block.tlb](https://github.com/ton-blockchain/ton/blob/master/crypto/block/block.tlb) and some types described in [lite_api.tl](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/lite_api.tl). -Go definitions of this types you can find in files: `account.go`, `transactions.go`, `models.go` ... +Go definitions of these types you can find in files: `ton/account.go`, `ton/transactions.go`, `ton/models.go` ... ## Chat diff --git a/abi/decoder_test.go b/abi/decoder_test.go index 181e25d6..ecfc1051 100644 --- a/abi/decoder_test.go +++ b/abi/decoder_test.go @@ -6,8 +6,8 @@ import ( "fmt" "testing" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/boc" + "github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/tvm" ) @@ -151,7 +151,7 @@ func TestSimpleGetMethod(t *testing.T) { dataBytes, _ := hex.DecodeString(c.Data) codeCell, _ := boc.DeserializeBoc(codeBytes) dataCell, _ := boc.DeserializeBoc(dataBytes) - account, _ := tongo.AccountIDFromRaw(c.Account) + account, _ := ton.AccountIDFromRaw(c.Account) var ( emulator *tvm.Emulator diff --git a/abi/generated_test.go b/abi/generated_test.go index 6c0056d3..1b124c8a 100644 --- a/abi/generated_test.go +++ b/abi/generated_test.go @@ -8,16 +8,15 @@ import ( "reflect" "testing" - "github.com/tonkeeper/tongo/liteapi" - - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/boc" + "github.com/tonkeeper/tongo/liteapi" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/tvm" ) -func mustToAddress(x string) tongo.AccountID { - accountID, err := tongo.AccountIDFromRaw(x) +func mustToAddress(x string) ton.AccountID { + accountID, err := ton.AccountIDFromRaw(x) if err != nil { panic(err) } @@ -25,7 +24,7 @@ func mustToAddress(x string) tongo.AccountID { } func mustToMsgAddress(x string) tlb.MsgAddress { - accountID, err := tongo.AccountIDFromRaw(x) + accountID, err := ton.AccountIDFromRaw(x) if err != nil { panic(err) } @@ -140,11 +139,11 @@ func TestGetMethods(t *testing.T) { Wallet: struct { Workchain uint32 Address tlb.Bits256 - }{0, tlb.Bits256(tongo.MustParseHash("f3b542fa6d15e4bba8c9aac63aa1b8a97d787ab7dcb34730e1e5a4e78e104b80"))}, + }{0, tlb.Bits256(ton.MustParseHash("f3b542fa6d15e4bba8c9aac63aa1b8a97d787ab7dcb34730e1e5a4e78e104b80"))}, Beneficiary: struct { Workchain uint32 Address tlb.Bits256 - }{0, tlb.Bits256(tongo.MustParseHash("e01675b731ed41f3a186a29d4a203068f744f68162cc370b0cde92f24ff97de5"))}, + }{0, tlb.Bits256(ton.MustParseHash("e01675b731ed41f3a186a29d4a203068f744f68162cc370b0cde92f24ff97de5"))}, Amount: 1000000000, Period: 2629800, StartTime: 1644413924, @@ -208,7 +207,7 @@ func TestGetMethods(t *testing.T) { if err != nil { t.Fatalf("DecodeString() failed: %v", err) } - accountID, err := tongo.AccountIDFromRaw(tt.account) + accountID, err := ton.AccountIDFromRaw(tt.account) if err != nil { t.Fatalf("AccountIDFromRaw() failed: %v", err) } @@ -248,7 +247,7 @@ func TestGetMethods(t *testing.T) { } func TestWhalesNominators(t *testing.T) { - address := tongo.MustParseAccountID("EQBI-wGVp_x0VFEjd7m9cEUD3tJ_bnxMSp0Tb9qz757ATEAM") + address := ton.MustParseAccountID("EQBI-wGVp_x0VFEjd7m9cEUD3tJ_bnxMSp0Tb9qz757ATEAM") client, err := liteapi.NewClientWithDefaultMainnet() if err != nil { t.Fatal(err) @@ -261,7 +260,7 @@ func TestWhalesNominators(t *testing.T) { if len(members.List.Keys()) == 0 { t.Fatal(len(members.List.Keys())) } - memberAddress := tongo.NewAccountId(0, members.List.Keys()[1]) + memberAddress := ton.NewAccountId(0, members.List.Keys()[1]) _, v, err = GetMember(context.Background(), client, address, memberAddress.ToMsgAddress()) if err != nil { t.Fatal(err) @@ -285,7 +284,7 @@ func TestWhalesNominators(t *testing.T) { } func mustAccountIDToMsgAddress(account string) tlb.MsgAddress { - accountID := tongo.MustParseAccountID(account) + accountID := ton.MustParseAccountID(account) return accountID.ToMsgAddress() } diff --git a/abi/generator.go b/abi/generator.go index f78c5c22..3a84a78b 100644 --- a/abi/generator.go +++ b/abi/generator.go @@ -105,8 +105,8 @@ func main() { for _, f := range [][]string{ {types, "types.go", `"github.com/tonkeeper/tongo/tlb"`}, {msgDecoder, "messages.go", `"fmt"`, `"github.com/tonkeeper/tongo/boc"`, `"github.com/tonkeeper/tongo/tlb"`}, - {getMethods, "get_methods.go", `"context"`, `"fmt"`, `"github.com/tonkeeper/tongo"`, `"github.com/tonkeeper/tongo/boc"`, `"github.com/tonkeeper/tongo/tlb"`}, - {invocationOrder, "ordering.go", `"context"`, `"github.com/tonkeeper/tongo"`}, + {getMethods, "get_methods.go", `"context"`, `"fmt"`, `"github.com/tonkeeper/tongo/ton"`, `"github.com/tonkeeper/tongo/boc"`, `"github.com/tonkeeper/tongo/tlb"`}, + {invocationOrder, "ordering.go", `"context"`, `"github.com/tonkeeper/tongo/ton"`}, } { file, err := os.Create(f[1]) if err != nil { diff --git a/abi/get_methods.go b/abi/get_methods.go index d2ba2289..f52de423 100644 --- a/abi/get_methods.go +++ b/abi/get_methods.go @@ -4,7 +4,7 @@ package abi import ( "context" "fmt" -"github.com/tonkeeper/tongo" +"github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" ) @@ -65,7 +65,7 @@ var KnownGetMethodsDecoder = map[string][]func(tlb.VmStack) (string, any, error) "seqno": {DecodeSeqnoResult}, } -var KnownSimpleGetMethods = map[int][]func(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error){ +var KnownSimpleGetMethods = map[int][]func(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error){ 66763: {GetFullDomain}, 69506: {GetTelemintTokenName}, 71463: {GetTorrentHash}, @@ -172,7 +172,7 @@ var ResultTypes = []interface{}{ } type Executor interface { - RunSmcMethodByID(ctx context.Context, accountID tongo.AccountID, methodID int, params tlb.VmStack) (uint32, tlb.VmStack, error) + RunSmcMethodByID(ctx context.Context, accountID ton.AccountID, methodID int, params tlb.VmStack) (uint32, tlb.VmStack, error) } type Dnsresolve_RecordsResult struct { @@ -180,7 +180,7 @@ type Dnsresolve_RecordsResult struct { Result tlb.DNSRecordSet } -func Dnsresolve(ctx context.Context, executor Executor, reqAccountID tongo.AccountID, domain []byte, category tlb.Int257) (string, any, error) { +func Dnsresolve(ctx context.Context, executor Executor, reqAccountID ton.AccountID, domain []byte, category tlb.Int257) (string, any, error) { stack := tlb.VmStack{} var ( val tlb.VmStackValue @@ -226,7 +226,7 @@ type GetAuctionInfoResult struct { AuctionEndTime uint64 } -func GetAuctionInfo(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetAuctionInfo(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 80697 for "get_auction_info" method @@ -259,7 +259,7 @@ type GetAuthorityAddressResult struct { Address tlb.MsgAddress } -func GetAuthorityAddress(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetAuthorityAddress(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 84760 for "get_authority_address" method @@ -292,7 +292,7 @@ type GetBillAddressResult struct { BillAddress tlb.MsgAddress } -func GetBillAddress(ctx context.Context, executor Executor, reqAccountID tongo.AccountID, userAddress tlb.MsgAddress) (string, any, error) { +func GetBillAddress(ctx context.Context, executor Executor, reqAccountID ton.AccountID, userAddress tlb.MsgAddress) (string, any, error) { stack := tlb.VmStack{} var ( val tlb.VmStackValue @@ -334,7 +334,7 @@ type GetBillAmountResult struct { Amount int64 } -func GetBillAmount(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetBillAmount(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 96705 for "get_bill_amount" method @@ -367,7 +367,7 @@ type GetChannelStateResult struct { State uint64 } -func GetChannelState(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetChannelState(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 106901 for "get_channel_state" method @@ -402,7 +402,7 @@ type GetCollectionDataResult struct { OwnerAddress tlb.MsgAddress } -func GetCollectionData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetCollectionData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 102491 for "get_collection_data" method @@ -435,7 +435,7 @@ type GetDomainResult struct { Domain string } -func GetDomain(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetDomain(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 119378 for "get_domain" method @@ -468,7 +468,7 @@ type GetEditorResult struct { Editor tlb.MsgAddress } -func GetEditor(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetEditor(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 90228 for "get_editor" method @@ -501,7 +501,7 @@ type GetFullDomainResult struct { Domain string } -func GetFullDomain(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetFullDomain(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 66763 for "get_full_domain" method @@ -538,7 +538,7 @@ type GetJettonDataResult struct { JettonWalletCode tlb.Any } -func GetJettonData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetJettonData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 106029 for "get_jetton_data" method @@ -571,7 +571,7 @@ type GetLastFillUpTimeResult struct { LastFillUpTime int64 } -func GetLastFillUpTime(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetLastFillUpTime(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 91481 for "get_last_fill_up_time" method @@ -607,7 +607,7 @@ type GetLockerBillDataResult struct { LastWithdrawTime uint32 } -func GetLockerBillData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetLockerBillData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 118274 for "get_locker_bill_data" method @@ -645,7 +645,7 @@ type GetLockerDataResult struct { UnlockPeriod uint32 } -func GetLockerData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetLockerData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 73490 for "get_locker_data" method @@ -680,7 +680,7 @@ type GetLpData_MegatonResult struct { LpToJettonPair tlb.Any } -func GetLpData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetLpData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 80035 for "get_lp_data" method @@ -719,7 +719,7 @@ type GetLpMiningData_MegatonResult struct { MiningRateCell tlb.Any } -func GetLpMiningData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetLpMiningData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 104122 for "get_lp_mining_data" method @@ -762,7 +762,7 @@ type GetLpSwapData_MegatonResult struct { JettonBPendingBalance tlb.Int257 } -func GetLpSwapData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetLpSwapData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 116242 for "get_lp_swap_data" method @@ -798,7 +798,7 @@ type GetMember_WhalesNominatorResult struct { MemberWithdraw int64 } -func GetMember(ctx context.Context, executor Executor, reqAccountID tongo.AccountID, member tlb.MsgAddress) (string, any, error) { +func GetMember(ctx context.Context, executor Executor, reqAccountID ton.AccountID, member tlb.MsgAddress) (string, any, error) { stack := tlb.VmStack{} var ( val tlb.VmStackValue @@ -840,7 +840,7 @@ type GetMembersRaw_WhalesNominatorResult struct { Members WhalesNominatorsMembersList } -func GetMembersRaw(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetMembersRaw(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 89295 for "get_members_raw" method @@ -878,7 +878,7 @@ type GetMiningData_MegatonResult struct { Unknown uint64 } -func GetMiningData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetMiningData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 96219 for "get_mining_data" method @@ -913,7 +913,7 @@ type GetNextProofInfoResult struct { MaxSpan uint32 } -func GetNextProofInfo(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetNextProofInfo(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 81490 for "get_next_proof_info" method @@ -946,7 +946,7 @@ type GetNftAddressByIndexResult struct { Address tlb.MsgAddress } -func GetNftAddressByIndex(ctx context.Context, executor Executor, reqAccountID tongo.AccountID, index tlb.Int257) (string, any, error) { +func GetNftAddressByIndex(ctx context.Context, executor Executor, reqAccountID ton.AccountID, index tlb.Int257) (string, any, error) { stack := tlb.VmStack{} var ( val tlb.VmStackValue @@ -985,7 +985,7 @@ type GetNftContentResult struct { Content tlb.FullContent } -func GetNftContent(ctx context.Context, executor Executor, reqAccountID tongo.AccountID, index tlb.Int257, individualContent tlb.Any) (string, any, error) { +func GetNftContent(ctx context.Context, executor Executor, reqAccountID ton.AccountID, index tlb.Int257, individualContent tlb.Any) (string, any, error) { stack := tlb.VmStack{} var ( val tlb.VmStackValue @@ -1033,7 +1033,7 @@ type GetNftDataResult struct { IndividualContent tlb.Any } -func GetNftData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetNftData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 102351 for "get_nft_data" method @@ -1068,7 +1068,7 @@ type GetNominatorDataResult struct { WithdrawFound bool } -func GetNominatorData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID, address tlb.Int257) (string, any, error) { +func GetNominatorData(ctx context.Context, executor Executor, reqAccountID ton.AccountID, address tlb.Int257) (string, any, error) { stack := tlb.VmStack{} var ( val tlb.VmStackValue @@ -1113,7 +1113,7 @@ type GetParams_WhalesNominatorResult struct { ReceiptPrice int64 } -func GetParams(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetParams(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 115150 for "get_params" method @@ -1149,7 +1149,7 @@ type GetPluginListResult struct { } } -func GetPluginList(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetPluginList(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 107653 for "get_plugin_list" method @@ -1212,7 +1212,7 @@ type GetPoolData_StonfiResult struct { CollectedToken1ProtocolFee uint64 } -func GetPoolData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetPoolData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 81689 for "get_pool_data" method @@ -1301,7 +1301,7 @@ type GetPoolFullDataResult struct { ProjectedSupply int64 } -func GetPoolFullData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetPoolFullData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 92229 for "get_pool_full_data" method @@ -1338,7 +1338,7 @@ type GetPoolStatusResult struct { BalanceWithdraw int64 } -func GetPoolStatus(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetPoolStatus(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 120146 for "get_pool_status" method @@ -1371,7 +1371,7 @@ type GetPublicKeyResult struct { PublicKey tlb.Int257 } -func GetPublicKey(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetPublicKey(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 78748 for "get_public_key" method @@ -1404,7 +1404,7 @@ type GetRevokedTimeResult struct { Time uint64 } -func GetRevokedTime(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetRevokedTime(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 97667 for "get_revoked_time" method @@ -1480,7 +1480,7 @@ type GetSaleData_GetgemsAuctionResult struct { IsCanceled bool } -func GetSaleData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetSaleData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 72748 for "get_sale_data" method @@ -1537,7 +1537,7 @@ type GetStakingStatusResult struct { ProxyStakeLockFinal bool } -func GetStakingStatus(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetStakingStatus(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 123928 for "get_staking_status" method @@ -1570,7 +1570,7 @@ type GetStorageContractAddressResult struct { StorageContractAddress tlb.MsgAddress } -func GetStorageContractAddress(ctx context.Context, executor Executor, reqAccountID tongo.AccountID, merkleHash tlb.Int257, fileSize uint64, client tlb.MsgAddress, torrentHash tlb.Int257) (string, any, error) { +func GetStorageContractAddress(ctx context.Context, executor Executor, reqAccountID ton.AccountID, merkleHash tlb.Int257, fileSize uint64, client tlb.MsgAddress, torrentHash tlb.Int257) (string, any, error) { stack := tlb.VmStack{} var ( val tlb.VmStackValue @@ -1628,7 +1628,7 @@ type GetStorageContractDataResult struct { TorrentHash tlb.Int257 } -func GetStorageContractData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetStorageContractData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 86593 for "get_storage_contract_data" method @@ -1665,7 +1665,7 @@ type GetStorageParamsResult struct { MaximalFileSize uint64 } -func GetStorageParams(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetStorageParams(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 104346 for "get_storage_params" method @@ -1715,7 +1715,7 @@ type GetSubscriptionDataResult struct { SubscriptionId uint64 } -func GetSubscriptionData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetSubscriptionData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 92260 for "get_subscription_data" method @@ -1748,7 +1748,7 @@ type GetSubwalletIdResult struct { SubwalletId uint32 } -func GetSubwalletId(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetSubwalletId(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 81467 for "get_subwallet_id" method @@ -1786,7 +1786,7 @@ type GetTelemintAuctionConfigResult struct { Duration int64 } -func GetTelemintAuctionConfig(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetTelemintAuctionConfig(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 129619 for "get_telemint_auction_config" method @@ -1823,7 +1823,7 @@ type GetTelemintAuctionStateResult struct { EndTime int64 } -func GetTelemintAuctionState(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetTelemintAuctionState(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 122498 for "get_telemint_auction_state" method @@ -1856,7 +1856,7 @@ type GetTelemintTokenNameResult struct { Beneficiar tlb.Text } -func GetTelemintTokenName(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetTelemintTokenName(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 69506 for "get_telemint_token_name" method @@ -1889,7 +1889,7 @@ type GetTorrentHashResult struct { TorrentHash tlb.Int257 } -func GetTorrentHash(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetTorrentHash(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 71463 for "get_torrent_hash" method @@ -1934,7 +1934,7 @@ type GetValidatorControllerDataResult struct { Sudoer tlb.MsgAddress } -func GetValidatorControllerData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetValidatorControllerData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 103232 for "get_validator_controller_data" method @@ -1967,7 +1967,7 @@ type GetWalletAddressResult struct { JettonWalletAddress tlb.MsgAddress } -func GetWalletAddress(ctx context.Context, executor Executor, reqAccountID tongo.AccountID, ownerAddress tlb.MsgAddress) (string, any, error) { +func GetWalletAddress(ctx context.Context, executor Executor, reqAccountID ton.AccountID, ownerAddress tlb.MsgAddress) (string, any, error) { stack := tlb.VmStack{} var ( val tlb.VmStackValue @@ -2012,7 +2012,7 @@ type GetWalletDataResult struct { JettonWalletCode tlb.Any } -func GetWalletData(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetWalletData(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 97026 for "get_wallet_data" method @@ -2047,7 +2047,7 @@ type GetWalletParamsResult struct { PublicKey tlb.Int257 } -func GetWalletParams(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func GetWalletParams(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 130271 for "get_wallet_params" method @@ -2080,7 +2080,7 @@ type IsActiveResult struct { IsActive bool } -func IsActive(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func IsActive(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 122058 for "is_active" method @@ -2113,7 +2113,7 @@ type IsPluginInstalledResult struct { Success bool } -func IsPluginInstalled(ctx context.Context, executor Executor, reqAccountID tongo.AccountID, workchain int32, addrHash tlb.Int257) (string, any, error) { +func IsPluginInstalled(ctx context.Context, executor Executor, reqAccountID ton.AccountID, workchain int32, addrHash tlb.Int257) (string, any, error) { stack := tlb.VmStack{} var ( val tlb.VmStackValue @@ -2159,7 +2159,7 @@ type ListNominatorsResult struct { } } -func ListNominators(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func ListNominators(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 111161 for "list_nominators" method @@ -2195,7 +2195,7 @@ type ListVotesResult struct { } } -func ListVotes(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func ListVotes(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 130309 for "list_votes" method @@ -2230,7 +2230,7 @@ type RoyaltyParamsResult struct { Destination tlb.MsgAddress } -func RoyaltyParams(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func RoyaltyParams(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 85719 for "royalty_params" method @@ -2263,7 +2263,7 @@ type SeqnoResult struct { State uint32 } -func Seqno(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) { +func Seqno(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) { stack := tlb.VmStack{} // MethodID = 85143 for "seqno" method diff --git a/abi/inspect.go b/abi/inspect.go index eec527f1..f5610045 100644 --- a/abi/inspect.go +++ b/abi/inspect.go @@ -4,9 +4,9 @@ import ( "context" "fmt" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/utils" ) @@ -55,7 +55,7 @@ func NewContractInspector(opts ...InspectorOption) *contractInspector { // The contract is not provided directly, // instead, it is expected that "executor" has been created with knowledge of the contract's code and data. // Executor must be ready to execute multiple different methods and must not rely on a particular order of execution. -func (ci contractInspector) InspectContract(ctx context.Context, code []byte, executor Executor, reqAccountID tongo.AccountID) (*ContractDescription, error) { +func (ci contractInspector) InspectContract(ctx context.Context, code []byte, executor Executor, reqAccountID ton.AccountID) (*ContractDescription, error) { if len(code) == 0 { return &ContractDescription{}, nil } @@ -163,7 +163,7 @@ func (ci ContractDescription) ImplementedInterfaces() []ContractInterface { } type codeInfo struct { - hash tongo.Bits256 + hash ton.Bits256 methods map[int64]struct{} } @@ -188,7 +188,7 @@ func getCodeInfo(code []byte) (*codeInfo, error) { if err != nil { return nil, err } - var hash tongo.Bits256 + var hash ton.Bits256 if err = hash.FromBytes(h); err != nil { return nil, err } diff --git a/abi/inspect_test.go b/abi/inspect_test.go index 1a9222c7..950bfdf9 100644 --- a/abi/inspect_test.go +++ b/abi/inspect_test.go @@ -8,8 +8,8 @@ import ( "sort" "testing" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/boc" + "github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/tvm" ) @@ -98,7 +98,7 @@ func Test_contractInspector_InspectContract(t *testing.T) { } var addr [32]byte copy(addr[:], address[:]) - account := tongo.AccountID{Address: addr, Workchain: 0} + account := ton.AccountID{Address: addr, Workchain: 0} ci := NewContractInspector() emulator, err := tvm.NewEmulator(codeCell[0], dataCell[0], mainnetConfig[0], tvm.WithLazyC7Optimization()) contractDescription, err := ci.InspectContract(context.Background(), codeBytes, emulator, account) diff --git a/abi/ordering.go b/abi/ordering.go index 7dff87da..cb4a1c96 100644 --- a/abi/ordering.go +++ b/abi/ordering.go @@ -5,7 +5,7 @@ package abi import ( "context" - "github.com/tonkeeper/tongo" + "github.com/tonkeeper/tongo/ton" ) type ContractInterface string @@ -42,7 +42,7 @@ const ( WhalesNominators ContractInterface = "whales_nominators" ) -type InvokeFn func(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) +type InvokeFn func(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) // MethodDescription describes a particular method and provides a function to execute it. type MethodDescription struct { diff --git a/abi/parser/generator.go b/abi/parser/generator.go index eb55cc48..ef2a3af8 100644 --- a/abi/parser/generator.go +++ b/abi/parser/generator.go @@ -17,7 +17,7 @@ import ( ) var defaultKnownTypes = map[string]string{ - "accountid": "tongo.AccountID", + "accountid": "ton.AccountID", "cell": "boc.Cell", "int8": "int8", "int32": "int32", @@ -86,7 +86,7 @@ func (g *Generator) GetMethods() (string, error) { var builder, methodMap, resultMap, decodersMap strings.Builder builder.WriteString(` type Executor interface { - RunSmcMethodByID(ctx context.Context, accountID tongo.AccountID, methodID int, params tlb.VmStack) (uint32, tlb.VmStack, error) + RunSmcMethodByID(ctx context.Context, accountID ton.AccountID, methodID int, params tlb.VmStack) (uint32, tlb.VmStack, error) } `) @@ -134,7 +134,7 @@ type Executor interface { builder.WriteRune('\n') } decodersMap.WriteString("}\n\n") - methodMap.WriteString("var KnownSimpleGetMethods = map[int][]func(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error){\n") + methodMap.WriteString("var KnownSimpleGetMethods = map[int][]func(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error){\n") for _, k := range utils.GetOrderedKeys(methods) { methodMap.WriteString(fmt.Sprintf("%d: {", k)) for _, m := range methods[k] { @@ -255,7 +255,7 @@ func (g *Generator) getMethod(m GetMethod, methodID int, methodName string) (str var builder strings.Builder var args []string - builder.WriteString(fmt.Sprintf("func %v(ctx context.Context, executor Executor, reqAccountID tongo.AccountID, ", m.GolangFunctionName())) + builder.WriteString(fmt.Sprintf("func %v(ctx context.Context, executor Executor, reqAccountID ton.AccountID, ", m.GolangFunctionName())) for _, s := range m.Input.StackValues { t, err := g.checkType(s.Type) diff --git a/abi/parser/invocation_order.tmpl b/abi/parser/invocation_order.tmpl index 8c6a57e0..92a270e8 100644 --- a/abi/parser/invocation_order.tmpl +++ b/abi/parser/invocation_order.tmpl @@ -8,7 +8,7 @@ const ( {{- end }} ) -type InvokeFn func(ctx context.Context, executor Executor, reqAccountID tongo.AccountID) (string, any, error) +type InvokeFn func(ctx context.Context, executor Executor, reqAccountID ton.AccountID) (string, any, error) // MethodDescription describes a particular method and provides a function to execute it. type MethodDescription struct { diff --git a/account.go b/account.go index 0a4f9366..535f65b6 100644 --- a/account.go +++ b/account.go @@ -1,173 +1,157 @@ package tongo import ( + "context" "encoding/base64" "encoding/binary" - "encoding/json" "fmt" - "io" "strings" + "sync" + "time" "github.com/snksoft/crc" + "github.com/tonkeeper/tongo/contract/dns" + "github.com/tonkeeper/tongo/liteapi" "github.com/tonkeeper/tongo/tlb" - "github.com/tonkeeper/tongo/utils" + "github.com/tonkeeper/tongo/ton" ) -type AccountID struct { - Workchain int32 - Address [32]byte -} +const ( + // DefaultRoot is the default root address used by the addressParser. + DefaultRoot = "-1:e56754f83426f69b09267bd876ac97c44821345b7e266bd956a7bfbfb98df35c" +) + +type AccountID = ton.AccountID func NewAccountId(id int32, addr [32]byte) *AccountID { return &AccountID{Workchain: id, Address: addr} } -func (id AccountID) String() string { - return id.ToRaw() +func AccountIDFromBase64Url(s string) (AccountID, error) { + return ton.AccountIDFromBase64Url(s) } -func (id AccountID) IsZero() bool { - for i := range id.Address { - if id.Address[i] != 0 { - return false - } - } - return true +func AccountIDFromRaw(s string) (AccountID, error) { + return ton.AccountIDFromRaw(s) } -func (id AccountID) MarshalJSON() ([]byte, error) { - return json.Marshal(id.ToRaw()) +func ParseAccountID(s string) (AccountID, error) { + return ton.ParseAccountID(s) } -func (id *AccountID) UnmarshalJSON(data []byte) error { - a, err := ParseAccountID(strings.Trim(string(data), "\"\n ")) - if err != nil { - return err - } - id.Workchain = a.Workchain - id.Address = a.Address - return nil +func MustParseAccountID(s string) AccountID { + return ton.MustParseAccountID(s) } -func (id AccountID) ToRaw() string { - return fmt.Sprintf("%v:%x", id.Workchain, id.Address) +func AccountIDFromTlb(a tlb.MsgAddress) (*AccountID, error) { + return ton.AccountIDFromTlb(a) } -func (id AccountID) ToHuman(bounce, testnet bool) string { - prefix := byte(0b00010001) - if testnet { - prefix |= 0b10000000 - } - if !bounce { - prefix |= 0b01000000 - } - buf := make([]byte, 36) - buf[0] = prefix - buf[1] = byte(id.Workchain) - copy(buf[2:34], id.Address[:]) - binary.BigEndian.PutUint16(buf[34:36], utils.Crc16(buf[:34])) - return base64.URLEncoding.EncodeToString(buf) +var defaultParser *addressParser + +// DefaultAddressParser returns a default address parser that works in the mainnet. +// Currently, there is no way to change the network. +// Take a look at NewAccountAddressParser to create a parser for a different network or with a different root address. +func DefaultAddressParser() *addressParser { + return defaultParser } -func (id AccountID) MarshalTL() ([]byte, error) { - payload := make([]byte, 36) - binary.LittleEndian.PutUint32(payload[:4], uint32(id.Workchain)) - copy(payload[4:36], id.Address[:]) - return payload, nil +func init() { + defaultParser = NewAccountAddressParser(&lazyResolver{}) } -func (id *AccountID) UnmarshalTL(r io.Reader) error { - var b [4]byte - _, err := io.ReadFull(r, b[:]) - if err != nil { - return err - } - id.Workchain = int32(binary.LittleEndian.Uint32(b[:])) - _, err = io.ReadFull(r, id.Address[:]) - return err +// addressParser converts a string of different formats to a ton.Address. +type addressParser struct { + resolver dnsResolver } -func (id *AccountID) ToMsgAddress() tlb.MsgAddress { - if id == nil { - return tlb.MsgAddress{ - SumType: "AddrNone", - } - } - return tlb.MsgAddress{ - SumType: "AddrStd", - AddrStd: struct { - Anycast tlb.Maybe[tlb.Anycast] - WorkchainId int8 - Address tlb.Bits256 - }{ - WorkchainId: int8(id.Workchain), - Address: id.Address, - }, +// ParseAddress parses a string of different formats to a ton.Address. +func ParseAddress(a string) (ton.Address, error) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + return DefaultAddressParser().ParseAddress(ctx, a) +} + +// dnsResolver provides a method to resolve a domain name to a list of DNS records. +type dnsResolver interface { + Resolve(context.Context, string) ([]tlb.DNSRecord, error) +} + +func NewAccountAddressParser(resolver dnsResolver) *addressParser { + return &addressParser{ + resolver: resolver, } } -func AccountIDFromBase64Url(s string) (AccountID, error) { - var aa AccountID - b, err := base64.URLEncoding.DecodeString(s) - if err != nil { - return AccountID{}, err +func (p *addressParser) ParseAddress(ctx context.Context, address string) (ton.Address, error) { + accountID, err := ton.AccountIDFromRaw(address) + if err == nil { + return ton.Address{ID: accountID, Bounce: true, StateInit: nil}, nil } - if len(b) != 36 { - return AccountID{}, fmt.Errorf("invalid account 'user friendly' form length: %v", s) + // ignore the error because we'll try dns in case of error + bytesAddress, _ := base64.URLEncoding.DecodeString(address) + if len(bytesAddress) == 36 { + checksum := uint64(binary.BigEndian.Uint16(bytesAddress[34:36])) + if checksum == crc.CalculateCRC(crc.XMODEM, bytesAddress[0:34]) { + bounce := bytesAddress[0]&0x11 == 0x11 + accountID.Workchain = int32(int8(bytesAddress[1])) + copy(accountID.Address[:], bytesAddress[2:34]) + return ton.Address{ID: accountID, Bounce: bounce, StateInit: nil}, nil + } } - checksum := uint64(binary.BigEndian.Uint16(b[34:36])) - if checksum != crc.CalculateCRC(crc.XMODEM, b[0:34]) { - return AccountID{}, fmt.Errorf("invalid checksum") + if !strings.Contains(address, ".") { + return ton.Address{}, fmt.Errorf("can't decode address %v", address) } - aa.Workchain = int32(int8(b[1])) - copy(aa.Address[:], b[2:34]) - return aa, nil -} - -func AccountIDFromRaw(s string) (AccountID, error) { - var ( - workchain int32 - address []byte - aa AccountID - ) - _, err := fmt.Sscanf(s, "%d:%x", &workchain, &address) + result, err := p.resolver.Resolve(ctx, address) if err != nil { - return AccountID{}, err + return ton.Address{}, err } - if len(address) != 32 { - return AccountID{}, fmt.Errorf("address len must be 32 bytes") + account := ton.Address{Bounce: true} + for _, r := range result { + if r.SumType == "DNSSmcAddress" { + accountID, err := ton.AccountIDFromTlb(r.DNSSmcAddress.Address) + if err != nil { + return ton.Address{}, err + } + if accountID == nil { + return ton.Address{}, fmt.Errorf("destination account is null") + } + account.ID = *accountID + for _, c := range r.DNSSmcAddress.SmcCapability.Interfaces { + if c == "wallet" { + account.Bounce = false + } + } + return account, nil + } } - aa.Workchain = workchain - copy(aa.Address[:], address) - return aa, nil + return ton.Address{}, fmt.Errorf("address not found") } -func ParseAccountID(s string) (AccountID, error) { - aa, err := AccountIDFromRaw(s) - if err != nil { - aa, err = AccountIDFromBase64Url(s) - if err != nil { - return AccountID{}, err - } - } - return aa, nil +// lazyResolver is a dnsResolver that creates a new dns resolver on the first call to Resolve. +type lazyResolver struct { + mu sync.Mutex + dns dnsResolver } -func MustParseAccountID(s string) AccountID { - aa, err := ParseAccountID(s) +func (l *lazyResolver) Resolve(ctx context.Context, s string) ([]tlb.DNSRecord, error) { + resolver, err := l.resolver() if err != nil { - panic(err) + return nil, err } - return aa + return resolver.Resolve(ctx, s) } -// TODO: replace pointer with nullable type -func AccountIDFromTlb(a tlb.MsgAddress) (*AccountID, error) { - switch a.SumType { - case "AddrNone", "AddrExtern": //todo: make something with external addresses - return nil, nil - case "AddrStd": - return &AccountID{Workchain: int32(a.AddrStd.WorkchainId), Address: a.AddrStd.Address}, nil +func (l *lazyResolver) resolver() (dnsResolver, error) { + l.mu.Lock() + defer l.mu.Unlock() + if l.dns != nil { + return l.dns, nil + } + cli, err := liteapi.NewClient(liteapi.Mainnet(), liteapi.FromEnvs()) + if err != nil { + return nil, fmt.Errorf("failed to create liteapi client: %w", err) } - return nil, fmt.Errorf("can not convert not std address to AccountId") + l.dns = dns.NewDNS(MustParseAccountID(DefaultRoot), cli) + return l.dns, nil } diff --git a/account/account_test.go b/account/account_test.go deleted file mode 100644 index 2655e645..00000000 --- a/account/account_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package account - -import ( - "encoding/json" - "testing" -) - -func TestAccountIDJsonUnmarshal(t *testing.T) { - input := []byte(`{"A": "-1:7014a79eb7a81cf37542a62b75defa99427580e6612f956d47caa0fe0ec5d05e"}`) - var a struct { - A ID - } - err := json.Unmarshal(input, &a) - if err != nil { - t.Fatal(err) - } - if a.A.Workchain != -1 { - t.Fatal("invalid workchain") - } - for i, b := range []byte{112, 20, 167, 158, 183, 168, 28, 243, 117, 66, 166, 43, 117, 222, 250, 153, 66, 117, 128, 230, 97, 47, 149, 109, 71, 202, 160, 254, 14, 197, 208, 94} { - if a.A.Address[i] != b { - t.Fatal("invalid address") - } - } -} - -func TestToMsgAddress(t *testing.T) { - ma := (*ID)(nil).ToMsgAddress() - if ma.SumType != "AddrNone" { - t.Fatal(ma.SumType) - } -} diff --git a/account/address.go b/account/address.go deleted file mode 100644 index f7808443..00000000 --- a/account/address.go +++ /dev/null @@ -1,115 +0,0 @@ -package account - -import ( - "context" - "encoding/base64" - "encoding/binary" - "fmt" - "strings" - "time" - - "github.com/snksoft/crc" - "github.com/tonkeeper/tongo" - "github.com/tonkeeper/tongo/contract/dns" - "github.com/tonkeeper/tongo/liteapi" - "github.com/tonkeeper/tongo/tlb" -) - -type executor interface { - RunSmcMethodByID(context.Context, ID, int, tlb.VmStack) (uint32, tlb.VmStack, error) -} - -type parser struct { - root tongo.AccountID - executor executor -} - -type ID = tongo.AccountID - -type Address struct { - ID - Bounce bool - StateInit *tlb.StateInit -} - -func (p *parser) Root(root ID) *parser { - p.root = root - return p -} - -func (p *parser) Executor(executor executor) *parser { - p.executor = executor - return p -} - -var DefaultParser *parser - -func init() { - DefaultParser = NewAccountParser() -} - -func Parser(a string) (Address, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - return DefaultParser.ParseAddress(ctx, a) -} - -func NewAccountParser() *parser { - defaultRoot := tongo.MustParseAccountID("-1:e56754f83426f69b09267bd876ac97c44821345b7e266bd956a7bfbfb98df35c") - return &parser{ - root: defaultRoot, - } -} - -func (p *parser) ParseAddress(ctx context.Context, address string) (Address, error) { - - accountID, err := tongo.AccountIDFromRaw(address) - if err == nil { - return Address{ID: accountID, Bounce: true, StateInit: nil}, nil - } - bytesAddress, _ := base64.URLEncoding.DecodeString(address) - if len(bytesAddress) == 36 { - checksum := uint64(binary.BigEndian.Uint16(bytesAddress[34:36])) - if checksum == crc.CalculateCRC(crc.XMODEM, bytesAddress[0:34]) { - bounce := bytesAddress[0]&0x11 == 0x11 - accountID.Workchain = int32(int8(bytesAddress[1])) - copy(accountID.Address[:], bytesAddress[2:34]) - return Address{ID: accountID, Bounce: bounce, StateInit: nil}, nil - } - } - if !strings.Contains(address, ".") { - return Address{}, fmt.Errorf("can't decode address %v", address) - } - if p.executor == nil { - var err error - p.executor, err = liteapi.NewClientWithDefaultMainnet() - if err != nil { - return Address{}, err - } - } - newDns := dns.NewDNS(p.root, p.executor) // import cycle in package/dns.go - result, err := newDns.Resolve(ctx, address) - if err != nil { - return Address{}, err - } - account := Address{Bounce: true} - for _, r := range result { - if r.SumType == "DNSSmcAddress" { - accountID, err := tongo.AccountIDFromTlb(r.DNSSmcAddress.Address) - if err != nil { - return Address{}, err - } - if accountID == nil { - return Address{}, fmt.Errorf("destination account is null") - } - account.ID = *accountID - for _, c := range r.DNSSmcAddress.SmcCapability.Interfaces { - if c == "wallet" { - account.Bounce = false - } - } - return account, nil - } - } - return Address{}, fmt.Errorf("address not found") -} diff --git a/account/address_test.go b/address_test.go similarity index 78% rename from account/address_test.go rename to address_test.go index d9e8e3e3..cc6a3b25 100644 --- a/account/address_test.go +++ b/address_test.go @@ -1,4 +1,4 @@ -package account +package tongo import ( "context" @@ -6,12 +6,12 @@ import ( ) func TestParseAddress(t *testing.T) { - accountParser := NewAccountParser() + parser := DefaultAddressParser() const ( - parseToHumanAddress int = 1 - parseToRawAddress = 2 - parseDnsToRawAddress = 3 + parseToHumanAddress = iota + parseToRawAddress + parseDnsToRawAddress ) type testCase struct { @@ -40,9 +40,15 @@ func TestParseAddress(t *testing.T) { request: "blackpepper.ton", response: "0:44556b55c15052eb44c6b75a9eccbc6280d32d598d12e975f435195795bb11d5", }, + { + name: "Parse dns to raw address", + typeParse: parseDnsToRawAddress, + request: "subbotin.ton", + response: "0:2cf3b5b8c891e517c9addbda1c0386a09ccacbb0e3faf630b51cfc8152325acb", + }, } { t.Run(test.name, func(t *testing.T) { - account, err := accountParser.ParseAddress(context.Background(), test.request) + account, err := parser.ParseAddress(context.Background(), test.request) if err != nil { t.Fatalf("failed parse %v address: %v", test.request, err) } diff --git a/bits.go b/bits.go index 7f075ffc..4351c4ca 100644 --- a/bits.go +++ b/bits.go @@ -1,130 +1,15 @@ package tongo import ( - "bytes" - "database/sql/driver" - "encoding/base64" - "encoding/hex" - "errors" - "fmt" - "github.com/tonkeeper/tongo/tlb" - "strings" + "github.com/tonkeeper/tongo/ton" ) -type Bits256 tlb.Bits256 - -func (h Bits256) Base64() string { - return base64.StdEncoding.EncodeToString(h[:]) -} - -func (h Bits256) Hex() string { - return fmt.Sprintf("%x", h[:]) -} -func (h *Bits256) FromBase64(s string) error { - b, err := base64.StdEncoding.DecodeString(s) - if err != nil { - return err - } - if len(b) != 32 { - return errors.New("invalid hash length") - } - copy(h[:], b) - return nil -} - -func (h *Bits256) FromBase64URL(s string) error { - b, err := base64.URLEncoding.DecodeString(s) - if err != nil { - return err - } - if len(b) != 32 { - return errors.New("invalid hash length") - } - copy(h[:], b) - return nil -} - -func (h *Bits256) FromHex(s string) error { - if strings.HasPrefix(s, "0x") { - s = s[2:] - } - b, err := hex.DecodeString(s) - if err != nil { - return err - } - if len(b) != 32 { - return errors.New("invalid hash length") - } - copy(h[:], b) - return nil -} - -func (h *Bits256) FromUnknownString(s string) error { - err := h.FromBase64(s) - if err == nil { - return nil - } - err = h.FromBase64URL(s) - if err == nil { - return nil - } - err = h.FromHex(s) - if err == nil { - return nil - } - return err -} - -func (h *Bits256) FromBytes(b []byte) error { - if len(b) != 32 { - return fmt.Errorf("can't scan []byte of len %d into Bits256, want %d", len(b), 32) - } - copy(h[:], b) - return nil -} +type Bits256 = ton.Bits256 func ParseHash(s string) (Bits256, error) { - var h Bits256 - err := h.FromUnknownString(s) - return h, err + return ton.ParseHash(s) } func MustParseHash(s string) Bits256 { - h, err := ParseHash(s) - if err != nil { - panic(err) - } - return h -} - -// Scan implements Scanner for database/sql. -func (h *Bits256) Scan(src interface{}) error { - srcB, ok := src.([]byte) - if !ok { - return fmt.Errorf("can't scan %T into Bits256", src) - } - if len(srcB) != 32 { - return fmt.Errorf("can't scan []byte of len %d into Bits256, want %d", len(srcB), 32) - } - copy(h[:], srcB) - return nil -} - -// Value implements valuer for database/sql. -func (h Bits256) Value() (driver.Value, error) { - return h[:], nil -} - -func (b Bits256) MarshalJSON() ([]byte, error) { - return fmt.Appendf(nil, "\"%x\"", b), nil -} - -func (b *Bits256) UnmarshalJSON(buf []byte) error { - var sl []byte - _, err := fmt.Fscanf(bytes.NewReader(buf), "\"%x\"", &sl) - if len(sl) != 32 { - return fmt.Errorf("can't parse 256bits %v", string(buf)) - } - copy(b[:], sl) - return err + return ton.MustParseHash(s) } diff --git a/block.go b/block.go index 460005d5..0de90de6 100644 --- a/block.go +++ b/block.go @@ -1,240 +1,41 @@ package tongo import ( - "encoding/binary" - "fmt" - "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" ) -type BlockID struct { - Workchain int32 - Shard uint64 - Seqno uint32 -} - -type BlockIDExt struct { - BlockID - RootHash Bits256 - FileHash Bits256 -} +type BlockID = ton.BlockID -func (id BlockIDExt) MarshalTL() ([]byte, error) { - payload := make([]byte, 80) - binary.LittleEndian.PutUint32(payload[:4], uint32(id.Workchain)) - binary.LittleEndian.PutUint64(payload[4:12], id.Shard) - binary.LittleEndian.PutUint32(payload[12:16], id.Seqno) - copy(payload[16:48], id.RootHash[:]) - copy(payload[48:80], id.FileHash[:]) - return payload, nil -} - -func (id *BlockIDExt) UnmarshalTL(data []byte) error { - if len(data) != 80 { - return fmt.Errorf("invalid data length") - } - id.Workchain = int32(binary.LittleEndian.Uint32(data[:4])) - id.Shard = binary.LittleEndian.Uint64(data[4:12]) - id.Seqno = binary.LittleEndian.Uint32(data[12:16]) - copy(id.RootHash[:], data[16:48]) - copy(id.FileHash[:], data[48:80]) - return nil -} +type BlockIDExt = ton.BlockIDExt func NewTonBlockId(fileHash, rootHash Bits256, seqno uint32, shard uint64, workchain int32) *BlockIDExt { - return &BlockIDExt{ - BlockID: BlockID{ - Workchain: workchain, - Shard: shard, - Seqno: seqno, - }, - FileHash: fileHash, - RootHash: rootHash, - } -} - -func (id BlockIDExt) String() string { - return fmt.Sprintf("(%d,%x,%d,%x,%x)", id.Workchain, id.Shard, id.Seqno, id.RootHash, id.FileHash) -} -func (id BlockID) String() string { - return fmt.Sprintf("(%d,%x,%d)", id.Workchain, id.Shard, id.Seqno) -} - -func getParents(blkPrevInfo tlb.BlkPrevInfo, afterSplit, afterMerge bool, shard uint64, workchain int32) ([]BlockIDExt, error) { - var parents []BlockIDExt - if !afterMerge { - if blkPrevInfo.SumType != "PrevBlkInfo" { - return nil, fmt.Errorf("two parent blocks may be only after merge") - } - blockID := BlockIDExt{ - BlockID: BlockID{ - Workchain: workchain, - Seqno: blkPrevInfo.PrevBlkInfo.Prev.SeqNo, - }, - FileHash: Bits256(blkPrevInfo.PrevBlkInfo.Prev.FileHash), - RootHash: Bits256(blkPrevInfo.PrevBlkInfo.Prev.RootHash), - } - if afterSplit { - blockID.Shard = shardParent(shard) - return []BlockIDExt{blockID}, nil - } - blockID.Shard = shard - return []BlockIDExt{blockID}, nil - } - - if blkPrevInfo.SumType != "PrevBlksInfo" { - return nil, fmt.Errorf("two parent blocks must be after merge") - } - - parents = append(parents, BlockIDExt{ - BlockID: BlockID{ - Seqno: blkPrevInfo.PrevBlksInfo.Prev1.SeqNo, - Shard: shardChild(shard, true), - Workchain: workchain, - }, - FileHash: Bits256(blkPrevInfo.PrevBlksInfo.Prev1.FileHash), - RootHash: Bits256(blkPrevInfo.PrevBlksInfo.Prev1.RootHash), - }) - - parents = append(parents, BlockIDExt{ - FileHash: Bits256(blkPrevInfo.PrevBlksInfo.Prev2.FileHash), - RootHash: Bits256(blkPrevInfo.PrevBlksInfo.Prev2.RootHash), - BlockID: BlockID{ - Seqno: blkPrevInfo.PrevBlksInfo.Prev2.SeqNo, - Shard: shardChild(shard, false), - Workchain: workchain, - }, - }) - - return parents, nil -} - -// td::uint64 x = td::lower_bit64(shard) >> 1; -// return left ? shard - x : shard + x; -func shardChild(shard uint64, left bool) uint64 { - x := (shard & (^shard + 1)) >> 1 - if left { - return shard - x - } - return shard + x -} - -// td::uint64 x = td::lower_bit64(shard); -// return (shard - x) | (x << 1); -func shardParent(shard uint64) uint64 { - x := shard & (^shard + 1) - return (shard - x) | (x << 1) -} - -func convertShardIdent(si tlb.ShardIdent) (workchain int32, shard uint64) { - shard = si.ShardPrefix - pow2 := uint64(1) << (63 - si.ShardPfxBits) - shard |= pow2 - return si.WorkchainID, shard + return ton.NewTonBlockId(fileHash, rootHash, seqno, shard, workchain) } func GetParents(i tlb.BlockInfo) ([]BlockIDExt, error) { - workchain, shard := convertShardIdent(i.Shard) - return getParents(i.PrevRef, i.AfterSplit, i.AfterMerge, shard, workchain) + return ton.GetParents(i) } func ToBlockId(s tlb.ShardDesc, workchain int32) BlockIDExt { - if s.SumType == "Old" { - return BlockIDExt{ - BlockID: BlockID{ - Workchain: workchain, - Shard: uint64(s.Old.NextValidatorShard), - Seqno: s.Old.SeqNo, - }, - RootHash: Bits256(s.Old.RootHash), - FileHash: Bits256(s.Old.FileHash), - } - } else { - return BlockIDExt{ - BlockID: BlockID{ - Workchain: workchain, - Shard: uint64(s.New.NextValidatorShard), - Seqno: s.New.SeqNo, - }, - RootHash: Bits256(s.New.RootHash), - FileHash: Bits256(s.New.FileHash), - } - } + return ton.ToBlockId(s, workchain) } func CreateExternalMessage(address AccountID, body *boc.Cell, init *tlb.StateInit, importFee tlb.Grams) (tlb.Message, error) { - // TODO: add either selection algorithm - var msg = tlb.Message{ - Info: tlb.CommonMsgInfo{ - SumType: "ExtInMsgInfo", - ExtInMsgInfo: &struct { - Src tlb.MsgAddress - Dest tlb.MsgAddress - ImportFee tlb.Grams - }{ - Src: (*AccountID)(nil).ToMsgAddress(), - Dest: address.ToMsgAddress(), - ImportFee: importFee, - }, - }, - Body: tlb.EitherRef[tlb.Any]{ - IsRight: true, - Value: tlb.Any(*body), - }, - } - if init != nil { - msg.Init.Exists = true - msg.Init.Value.IsRight = true - msg.Init.Value.Value = *init - } - return msg, nil + return ton.CreateExternalMessage(address, body, init, importFee) } // ShardIDs returns a list of IDs of shard blocks this block refers to. func ShardIDs(blk *tlb.Block) []BlockIDExt { - if !blk.Extra.Custom.Exists { - return nil - } - items := blk.Extra.Custom.Value.Value.ShardHashes.Items() - shardsCount := 0 - for _, item := range items { - for _, x := range item.Value.Value.BinTree.Values { - if x.SeqNo() == 0 { - continue - } - shardsCount += 1 - } - } - if shardsCount == 0 { - return nil - } - shards := make([]BlockIDExt, 0, shardsCount) - for _, item := range items { - for _, shardDesc := range item.Value.Value.BinTree.Values { - if shardDesc.SeqNo() == 0 { - continue - } - shards = append(shards, ToBlockId(shardDesc, int32(item.Key))) - } - } - return shards + return ton.ShardIDs(blk) } // ParseBlockID tries to construct BlockID from the given string. func ParseBlockID(s string) (BlockID, error) { - var id BlockID - _, err := fmt.Sscanf(s, "(%d,%x,%d)", &id.Workchain, &id.Shard, &id.Seqno) - if err != nil { - return BlockID{}, err - } - return id, nil + return ton.ParseBlockID(s) } func MustParseBlockID(s string) BlockID { - id, err := ParseBlockID(s) - if err != nil { - panic(err) - } - return id + return ton.MustParseBlockID(s) } diff --git a/cmd/func-compiler/main.go b/cmd/func-compiler/main.go index 7ffe3eb5..f99d398f 100644 --- a/cmd/func-compiler/main.go +++ b/cmd/func-compiler/main.go @@ -2,11 +2,12 @@ package main import ( "fmt" - "github.com/tonkeeper/tongo/code" "log" "os" "path" "strings" + + "github.com/tonkeeper/tongo/code" ) func main() { diff --git a/connect/v1.go b/connect/v1.go index ebce0157..e354454b 100644 --- a/connect/v1.go +++ b/connect/v1.go @@ -3,6 +3,7 @@ package connect import ( "encoding/base64" "fmt" + "golang.org/x/crypto/nacl/sign" ) diff --git a/contract/dns/dns.go b/contract/dns/dns.go index c221b111..f9d5f719 100644 --- a/contract/dns/dns.go +++ b/contract/dns/dns.go @@ -2,15 +2,17 @@ package dns import ( "context" + "errors" "fmt" - "github.com/tonkeeper/tongo" + "strings" + "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" - "strings" + "github.com/tonkeeper/tongo/ton" ) type executor interface { - RunSmcMethodByID(context.Context, tongo.AccountID, int, tlb.VmStack) (uint32, tlb.VmStack, error) + RunSmcMethodByID(context.Context, ton.AccountID, int, tlb.VmStack) (uint32, tlb.VmStack, error) } var ( @@ -18,13 +20,13 @@ var ( ) type DNS struct { - root tongo.AccountID + root ton.AccountID executor executor } // NewDNS // If root == nil then use root from network config -func NewDNS(root tongo.AccountID, e executor) *DNS { +func NewDNS(root ton.AccountID, e executor) *DNS { return &DNS{ root: root, executor: e, @@ -33,7 +35,7 @@ func NewDNS(root tongo.AccountID, e executor) *DNS { func (d *DNS) Resolve(ctx context.Context, domain string) ([]tlb.DNSRecord, error) { if d.executor == nil { - return nil, tongo.BlockchainInterfaceIsNil + return nil, errors.New("blockchain interface is nil") } if domain == "" { domain = "." @@ -46,7 +48,7 @@ func (d *DNS) Resolve(ctx context.Context, domain string) ([]tlb.DNSRecord, erro return r, err } -func (d *DNS) resolve(ctx context.Context, resolver tongo.AccountID, dom []byte) ([]tlb.DNSRecord, error) { +func (d *DNS) resolve(ctx context.Context, resolver ton.AccountID, dom []byte) ([]tlb.DNSRecord, error) { n := int64(len(dom)) stack := tlb.VmStack{} val, err := tlb.TlbStructToVmCellSlice(dom) @@ -96,7 +98,7 @@ func (d *DNS) resolve(ctx context.Context, resolver tongo.AccountID, dom []byte) if record.SumType != "DNSNextResolver" { return nil, fmt.Errorf("should be next resolver") } - account, err := tongo.AccountIDFromTlb(record.DNSNextResolver) + account, err := ton.AccountIDFromTlb(record.DNSNextResolver) if err != nil { return nil, err } diff --git a/contract/dns/dns_test.go b/contract/dns/dns_test.go index 1a823285..7126b6d8 100644 --- a/contract/dns/dns_test.go +++ b/contract/dns/dns_test.go @@ -3,10 +3,11 @@ package dns import ( "context" "fmt" - "github.com/tonkeeper/tongo" - "github.com/tonkeeper/tongo/liteapi" "log" "testing" + + "github.com/tonkeeper/tongo/liteapi" + "github.com/tonkeeper/tongo/ton" ) func TestResolve(t *testing.T) { @@ -36,7 +37,7 @@ func TestResolve(t *testing.T) { t.Fatalf("Unable to resolve domain: %v", err) } if c.success { - a, _ := tongo.AccountIDFromTlb(res[0].DNSSmcAddress.Address) + a, _ := ton.AccountIDFromTlb(res[0].DNSSmcAddress.Address) if a.ToRaw() != c.wallet { t.Fatal("invalid wallet") } diff --git a/contract/jetton/jetton.go b/contract/jetton/jetton.go index b356436b..bf28b7a8 100644 --- a/contract/jetton/jetton.go +++ b/contract/jetton/jetton.go @@ -2,34 +2,36 @@ package jetton import ( "context" + "errors" "math/big" "strconv" "time" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/abi" "github.com/tonkeeper/tongo/boc" + "github.com/tonkeeper/tongo/tep64" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/wallet" ) type blockchain interface { - GetJettonWallet(ctx context.Context, master, owner tongo.AccountID) (tongo.AccountID, error) - GetJettonData(ctx context.Context, master tongo.AccountID) (tongo.JettonMetadata, error) - GetJettonBalance(ctx context.Context, jettonWallet tongo.AccountID) (*big.Int, error) + GetJettonWallet(ctx context.Context, master, owner ton.AccountID) (ton.AccountID, error) + GetJettonData(ctx context.Context, master ton.AccountID) (tep64.Metadata, error) + GetJettonBalance(ctx context.Context, jettonWallet ton.AccountID) (*big.Int, error) } type Jetton struct { - Master tongo.AccountID + Master ton.AccountID blockchain blockchain } type TransferMessage struct { Jetton *Jetton - Sender tongo.AccountID + Sender ton.AccountID JettonAmount *big.Int - Destination tongo.AccountID - ResponseDestination *tongo.AccountID + Destination ton.AccountID + ResponseDestination *ton.AccountID AttachedTon tlb.Grams ForwardTonAmount tlb.Grams ForwardPayload *boc.Cell @@ -74,16 +76,16 @@ func (tm TransferMessage) ToInternal() (tlb.Message, uint8, error) { return m.ToInternal() } -func New(master tongo.AccountID, blockchain blockchain) *Jetton { +func New(master ton.AccountID, blockchain blockchain) *Jetton { return &Jetton{ Master: master, blockchain: blockchain, } } -func (j *Jetton) GetBalance(ctx context.Context, owner tongo.AccountID) (*big.Int, error) { +func (j *Jetton) GetBalance(ctx context.Context, owner ton.AccountID) (*big.Int, error) { if j.blockchain == nil { - return nil, tongo.BlockchainInterfaceIsNil + return nil, errors.New("blockchain interface is nil") } jettonWallet, err := j.blockchain.GetJettonWallet(ctx, j.Master, owner) if err != nil { @@ -92,16 +94,16 @@ func (j *Jetton) GetBalance(ctx context.Context, owner tongo.AccountID) (*big.In return j.blockchain.GetJettonBalance(ctx, jettonWallet) } -func (j *Jetton) GetJettonWallet(ctx context.Context, owner tongo.AccountID) (tongo.AccountID, error) { +func (j *Jetton) GetJettonWallet(ctx context.Context, owner ton.AccountID) (ton.AccountID, error) { if j.blockchain == nil { - return tongo.AccountID{}, tongo.BlockchainInterfaceIsNil + return ton.AccountID{}, errors.New("blockchain interface is nil") } return j.blockchain.GetJettonWallet(ctx, j.Master, owner) } func (j *Jetton) GetDecimals(ctx context.Context) (int, error) { if j.blockchain == nil { - return 0, tongo.BlockchainInterfaceIsNil + return 0, errors.New("blockchain interface is nil") } data, err := j.blockchain.GetJettonData(ctx, j.Master) if err != nil { diff --git a/contract/jetton/jetton_test.go b/contract/jetton/jetton_test.go index 164309f9..4780d4e7 100644 --- a/contract/jetton/jetton_test.go +++ b/contract/jetton/jetton_test.go @@ -5,13 +5,14 @@ import ( "crypto/ed25519" "encoding/base64" "fmt" - "github.com/tonkeeper/tongo" - "github.com/tonkeeper/tongo/liteapi" - "github.com/tonkeeper/tongo/wallet" "log" "math/big" "testing" "time" + + "github.com/tonkeeper/tongo/liteapi" + "github.com/tonkeeper/tongo/ton" + "github.com/tonkeeper/tongo/wallet" ) func initDefaultWallet(blockchain *liteapi.Client) wallet.Wallet { @@ -27,7 +28,7 @@ func initDefaultWallet(blockchain *liteapi.Client) wallet.Wallet { func TestSendJetton(t *testing.T) { t.Skip() - recipientAddr, _ := tongo.AccountIDFromRaw("0:507dea7d606f22d9e85678d3eede39bbe133a868d2a0e3e07f5502cb70b8a512") + recipientAddr, _ := ton.AccountIDFromRaw("0:507dea7d606f22d9e85678d3eede39bbe133a868d2a0e3e07f5502cb70b8a512") client, err := liteapi.NewClientWithDefaultTestnet() if err != nil { @@ -35,7 +36,7 @@ func TestSendJetton(t *testing.T) { } w := initDefaultWallet(client) - master, _ := tongo.ParseAccountID("kQCKt2WPGX-fh0cIAz38Ljd_OKQjoZE_cqk7QrYGsNP6wfP0") + master, _ := ton.ParseAccountID("kQCKt2WPGX-fh0cIAz38Ljd_OKQjoZE_cqk7QrYGsNP6wfP0") j := New(master, client) b, err := j.GetBalance(context.Background(), w.GetAddress()) if err != nil { @@ -51,7 +52,7 @@ func TestSendJetton(t *testing.T) { Jetton: j, JettonAmount: amount, Destination: recipientAddr, - AttachedTon: tongo.OneTON / 2, + AttachedTon: ton.OneTON / 2, ForwardTonAmount: 200_000_000, } err = w.Send(context.Background(), jettonTransfer) diff --git a/contract/nft/nft.go b/contract/nft/nft.go index e2963e7e..c36aff10 100644 --- a/contract/nft/nft.go +++ b/contract/nft/nft.go @@ -6,25 +6,25 @@ import ( "math/big" "time" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/abi" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/wallet" ) type Item struct { - Address tongo.AccountID - Collection *tongo.AccountID - Owner *tongo.AccountID + Address ton.AccountID + Collection *ton.AccountID + Owner *ton.AccountID } type sender interface { Send(context.Context, ...wallet.Sendable) error - GetAddress() tongo.AccountID + GetAddress() ton.AccountID } -func (item Item) Transfer(ctx context.Context, sender sender, destination tongo.AccountID) error { +func (item Item) Transfer(ctx context.Context, sender sender, destination ton.AccountID) error { if item.Owner != nil && sender.GetAddress() != *item.Owner { return errors.New("sender is not the item owner") } @@ -32,16 +32,16 @@ func (item Item) Transfer(ctx context.Context, sender sender, destination tongo. ItemAddress: item.Address, Destination: destination, ResponseDestination: sender.GetAddress(), - AttachedTon: tongo.OneTON / 20, + AttachedTon: ton.OneTON / 20, ForwardTon: 0, } return sender.Send(ctx, transfer) } type ItemTransferMessage struct { - ItemAddress tongo.AccountID - Destination tongo.AccountID - ResponseDestination tongo.AccountID + ItemAddress ton.AccountID + Destination ton.AccountID + ResponseDestination ton.AccountID AttachedTon tlb.Grams ForwardTon tlb.Grams ForwardPayload *boc.Cell diff --git a/examples/func-testing/example_test.go b/examples/func-testing/example_test.go index 6c68c66f..0cdd518d 100644 --- a/examples/func-testing/example_test.go +++ b/examples/func-testing/example_test.go @@ -2,12 +2,13 @@ package func_testing import ( "context" - "github.com/tonkeeper/tongo" + "testing" + "github.com/tonkeeper/tongo/code" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/tontest" "github.com/tonkeeper/tongo/txemulator" - "testing" ) const SOURCE_CODE = ` @@ -88,7 +89,7 @@ func TestExample(t *testing.T) { t.Fatal(err) } - payTo := tongo.MustParseAccountID("0:ea27294687663e7c460be08e5bcef9341ae3ba6a1e2c4b0448b2f51e5eb45298") + payTo := ton.MustParseAccountID("0:ea27294687663e7c460be08e5bcef9341ae3ba6a1e2c4b0448b2f51e5eb45298") initData := struct { Counter uint64 @@ -107,7 +108,7 @@ func TestExample(t *testing.T) { testAccount := tontest.Account(). StateInit(tontest.MustAnyToCell(codeBoc), tontest.MustAnyToCell(initData)). - Balance(tongo.OneTON). + Balance(ton.OneTON). MustShardAccount() tracer, err := txemulator.NewTraceBuilder( diff --git a/examples/jetton/main.go b/examples/jetton/main.go index 483cddb8..a52a4c58 100644 --- a/examples/jetton/main.go +++ b/examples/jetton/main.go @@ -4,13 +4,14 @@ import ( "context" "crypto/ed25519" "encoding/base64" + "log" + "math/big" + "time" + "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/contract/jetton" "github.com/tonkeeper/tongo/liteapi" "github.com/tonkeeper/tongo/wallet" - "log" - "math/big" - "time" ) func main() { diff --git a/liteapi/client.go b/liteapi/client.go index 5f704bfa..93a150ce 100644 --- a/liteapi/client.go +++ b/liteapi/client.go @@ -11,15 +11,14 @@ import ( "sync" "time" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/config" + "github.com/tonkeeper/tongo/liteapi/pool" "github.com/tonkeeper/tongo/liteclient" "github.com/tonkeeper/tongo/tl" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/utils" - - "github.com/tonkeeper/tongo/liteapi/pool" ) const ( @@ -51,7 +50,7 @@ type Client struct { pool *pool.FailoverPool mu sync.RWMutex - targetBlockID *tongo.BlockIDExt + targetBlockID *ton.BlockIDExt } // Options holds parameters to configure a lite api instance. @@ -185,7 +184,7 @@ func NewClient(opts ...Option) (*Client, error) { return &client, nil } -func (c *Client) targetBlockOr(blockID tongo.BlockIDExt) tongo.BlockIDExt { +func (c *Client) targetBlockOr(blockID ton.BlockIDExt) ton.BlockIDExt { c.mu.RLock() defer c.mu.RUnlock() if c.targetBlockID == nil { @@ -194,7 +193,7 @@ func (c *Client) targetBlockOr(blockID tongo.BlockIDExt) tongo.BlockIDExt { return *c.targetBlockID } -func (c *Client) WithBlock(block tongo.BlockIDExt) *Client { +func (c *Client) WithBlock(block ton.BlockIDExt) *Client { return &Client{ pool: c.pool, targetBlockID: &block, @@ -226,7 +225,7 @@ func (c *Client) GetVersion(ctx context.Context) (liteclient.LiteServerVersionC, return client.LiteServerGetVersion(ctx) } -func (c *Client) GetBlock(ctx context.Context, blockID tongo.BlockIDExt) (tlb.Block, error) { +func (c *Client) GetBlock(ctx context.Context, blockID ton.BlockIDExt) (tlb.Block, error) { res, err := c.GetBlockRaw(ctx, blockID) if err != nil { return tlb.Block{}, err @@ -246,7 +245,7 @@ func (c *Client) GetBlock(ctx context.Context, blockID tongo.BlockIDExt) (tlb.Bl return data, nil } -func (c *Client) GetBlockRaw(ctx context.Context, blockID tongo.BlockIDExt) (liteclient.LiteServerBlockDataC, error) { +func (c *Client) GetBlockRaw(ctx context.Context, blockID ton.BlockIDExt) (liteclient.LiteServerBlockDataC, error) { client, err := c.pool.BestClientByBlockID(ctx, blockID.BlockID) if err != nil { return liteclient.LiteServerBlockDataC{}, err @@ -258,16 +257,16 @@ func (c *Client) GetBlockRaw(ctx context.Context, blockID tongo.BlockIDExt) (lit return res, err } -func (c *Client) GetState(ctx context.Context, blockID tongo.BlockIDExt) ([]byte, tongo.Bits256, tongo.Bits256, error) { +func (c *Client) GetState(ctx context.Context, blockID ton.BlockIDExt) ([]byte, ton.Bits256, ton.Bits256, error) { res, err := c.GetStateRaw(ctx, blockID) if err != nil { - return nil, tongo.Bits256{}, tongo.Bits256{}, err + return nil, ton.Bits256{}, ton.Bits256{}, err } // TODO: implement state tlb decoding - return res.Data, tongo.Bits256(res.RootHash), tongo.Bits256(res.FileHash), nil + return res.Data, ton.Bits256(res.RootHash), ton.Bits256(res.FileHash), nil } -func (c *Client) GetStateRaw(ctx context.Context, blockID tongo.BlockIDExt) (liteclient.LiteServerBlockStateC, error) { +func (c *Client) GetStateRaw(ctx context.Context, blockID ton.BlockIDExt) (liteclient.LiteServerBlockStateC, error) { client, err := c.pool.BestClientByBlockID(ctx, blockID.BlockID) if err != nil { return liteclient.LiteServerBlockStateC{}, err @@ -279,7 +278,7 @@ func (c *Client) GetStateRaw(ctx context.Context, blockID tongo.BlockIDExt) (lit return res, nil } -func (c *Client) GetBlockHeader(ctx context.Context, blockID tongo.BlockIDExt, mode uint32) (tlb.BlockInfo, error) { +func (c *Client) GetBlockHeader(ctx context.Context, blockID ton.BlockIDExt, mode uint32) (tlb.BlockInfo, error) { res, err := c.GetBlockHeaderRaw(ctx, blockID, mode) if err != nil { return tlb.BlockInfo{}, err @@ -288,7 +287,7 @@ func (c *Client) GetBlockHeader(ctx context.Context, blockID tongo.BlockIDExt, m return info, err } -func (c *Client) GetBlockHeaderRaw(ctx context.Context, blockID tongo.BlockIDExt, mode uint32) (liteclient.LiteServerBlockHeaderC, error) { +func (c *Client) GetBlockHeaderRaw(ctx context.Context, blockID ton.BlockIDExt, mode uint32) (liteclient.LiteServerBlockHeaderC, error) { client, err := c.pool.BestClientByBlockID(ctx, blockID.BlockID) if err != nil { return liteclient.LiteServerBlockHeaderC{}, err @@ -303,10 +302,10 @@ func (c *Client) GetBlockHeaderRaw(ctx context.Context, blockID tongo.BlockIDExt return res, nil } -func (c *Client) LookupBlock(ctx context.Context, blockID tongo.BlockID, mode uint32, lt *uint64, utime *uint32) (tongo.BlockIDExt, tlb.BlockInfo, error) { +func (c *Client) LookupBlock(ctx context.Context, blockID ton.BlockID, mode uint32, lt *uint64, utime *uint32) (ton.BlockIDExt, tlb.BlockInfo, error) { client, err := c.pool.BestClientByBlockID(ctx, blockID) if err != nil { - return tongo.BlockIDExt{}, tlb.BlockInfo{}, err + return ton.BlockIDExt{}, tlb.BlockInfo{}, err } res, err := client.LiteServerLookupBlock(ctx, liteclient.LiteServerLookupBlockRequest{ Mode: mode, @@ -319,25 +318,25 @@ func (c *Client) LookupBlock(ctx context.Context, blockID tongo.BlockID, mode ui Utime: utime, }) if err != nil { - return tongo.BlockIDExt{}, tlb.BlockInfo{}, err + return ton.BlockIDExt{}, tlb.BlockInfo{}, err } return decodeBlockHeader(res) } -func decodeBlockHeader(header liteclient.LiteServerBlockHeaderC) (tongo.BlockIDExt, tlb.BlockInfo, error) { +func decodeBlockHeader(header liteclient.LiteServerBlockHeaderC) (ton.BlockIDExt, tlb.BlockInfo, error) { cells, err := boc.DeserializeBoc(header.HeaderProof) if err != nil { - return tongo.BlockIDExt{}, tlb.BlockInfo{}, err + return ton.BlockIDExt{}, tlb.BlockInfo{}, err } if len(cells) != 1 { - return tongo.BlockIDExt{}, tlb.BlockInfo{}, boc.ErrNotSingleRoot + return ton.BlockIDExt{}, tlb.BlockInfo{}, boc.ErrNotSingleRoot } var proof struct { Proof tlb.MerkleProof[tlb.BlockHeader] } err = tlb.Unmarshal(cells[0], &proof) if err != nil { - return tongo.BlockIDExt{}, tlb.BlockInfo{}, err + return ton.BlockIDExt{}, tlb.BlockInfo{}, err } return header.Id.ToBlockIdExt(), proof.Proof.VirtualRoot.Info, nil // TODO: maybe decode more } @@ -355,7 +354,7 @@ func (c *Client) SendMessage(ctx context.Context, payload []byte) (uint32, error return res.Status, err } -func (c *Client) RunSmcMethodByID(ctx context.Context, accountID tongo.AccountID, methodID int, params tlb.VmStack) (uint32, tlb.VmStack, error) { +func (c *Client) RunSmcMethodByID(ctx context.Context, accountID ton.AccountID, methodID int, params tlb.VmStack) (uint32, tlb.VmStack, error) { cell := boc.NewCell() err := tlb.Marshal(cell, params) if err != nil { @@ -397,14 +396,14 @@ func (c *Client) RunSmcMethodByID(ctx context.Context, accountID tongo.AccountID func (c *Client) RunSmcMethod( ctx context.Context, - accountID tongo.AccountID, + accountID ton.AccountID, method string, params tlb.VmStack, ) (uint32, tlb.VmStack, error) { return c.RunSmcMethodByID(ctx, accountID, utils.MethodIdFromName(method), params) } -func (c *Client) GetAccountState(ctx context.Context, accountID tongo.AccountID) (tlb.ShardAccount, error) { +func (c *Client) GetAccountState(ctx context.Context, accountID ton.AccountID) (tlb.ShardAccount, error) { res, err := c.GetAccountStateRaw(ctx, accountID) if err != nil { return tlb.ShardAccount{}, err @@ -428,7 +427,7 @@ func (c *Client) GetAccountState(ctx context.Context, accountID tongo.AccountID) return tlb.ShardAccount{Account: acc, LastTransHash: hash, LastTransLt: lt}, err } -func (c *Client) GetAccountStateRaw(ctx context.Context, accountID tongo.AccountID) (liteclient.LiteServerAccountStateC, error) { +func (c *Client) GetAccountStateRaw(ctx context.Context, accountID ton.AccountID) (liteclient.LiteServerAccountStateC, error) { client, masterHead, err := c.pool.BestClientByAccountID(ctx, accountID) if err != nil { return liteclient.LiteServerAccountStateC{}, err @@ -444,7 +443,7 @@ func (c *Client) GetAccountStateRaw(ctx context.Context, accountID tongo.Account return res, nil } -func decodeAccountDataFromProof(bocBytes []byte, account tongo.AccountID) (uint64, tlb.Bits256, error) { +func decodeAccountDataFromProof(bocBytes []byte, account ton.AccountID) (uint64, tlb.Bits256, error) { cells, err := boc.DeserializeBoc(bocBytes) if err != nil { return 0, tlb.Bits256{}, err @@ -471,19 +470,19 @@ func decodeAccountDataFromProof(bocBytes []byte, account tongo.AccountID) (uint6 func (c *Client) GetShardInfo( ctx context.Context, - blockID tongo.BlockIDExt, + blockID ton.BlockIDExt, workchain uint32, shard uint64, exact bool, -) (tongo.BlockIDExt, error) { +) (ton.BlockIDExt, error) { res, err := c.GetShardInfoRaw(ctx, blockID, workchain, shard, exact) if err != nil { - return tongo.BlockIDExt{}, err + return ton.BlockIDExt{}, err } return res.Id.ToBlockIdExt(), nil } -func (c *Client) GetShardInfoRaw(ctx context.Context, blockID tongo.BlockIDExt, workchain uint32, shard uint64, exact bool) (liteclient.LiteServerShardInfoC, error) { +func (c *Client) GetShardInfoRaw(ctx context.Context, blockID ton.BlockIDExt, workchain uint32, shard uint64, exact bool) (liteclient.LiteServerShardInfoC, error) { client, _, err := c.pool.BestMasterchainClient(ctx) if err != nil { return liteclient.LiteServerShardInfoC{}, err @@ -500,7 +499,7 @@ func (c *Client) GetShardInfoRaw(ctx context.Context, blockID tongo.BlockIDExt, return res, nil } -func (c *Client) GetAllShardsInfo(ctx context.Context, blockID tongo.BlockIDExt) ([]tongo.BlockIDExt, error) { +func (c *Client) GetAllShardsInfo(ctx context.Context, blockID ton.BlockIDExt) ([]ton.BlockIDExt, error) { res, err := c.GetAllShardsInfoRaw(ctx, blockID) if err != nil { return nil, err @@ -517,17 +516,17 @@ func (c *Client) GetAllShardsInfo(ctx context.Context, blockID tongo.BlockIDExt) if err != nil { return nil, err } - var shards []tongo.BlockIDExt + var shards []ton.BlockIDExt for i, v := range inf.ShardHashes.Values() { wc := inf.ShardHashes.Keys()[i] for _, vv := range v.Value.BinTree.Values { - shards = append(shards, tongo.ToBlockId(vv, int32(wc))) + shards = append(shards, ton.ToBlockId(vv, int32(wc))) } } return shards, nil } -func (c *Client) GetAllShardsInfoRaw(ctx context.Context, blockID tongo.BlockIDExt) (liteclient.LiteServerAllShardsInfoC, error) { +func (c *Client) GetAllShardsInfoRaw(ctx context.Context, blockID ton.BlockIDExt) (liteclient.LiteServerAllShardsInfoC, error) { client, _, err := c.pool.BestMasterchainClient(ctx) if err != nil { return liteclient.LiteServerAllShardsInfoC{}, err @@ -542,13 +541,13 @@ func (c *Client) GetAllShardsInfoRaw(ctx context.Context, blockID tongo.BlockIDE func (c *Client) GetOneTransactionFromBlock( ctx context.Context, - accountID tongo.AccountID, - blockId tongo.BlockIDExt, + accountID ton.AccountID, + blockId ton.BlockIDExt, lt uint64, -) (tongo.Transaction, error) { +) (ton.Transaction, error) { client, _, err := c.pool.BestClientByAccountID(ctx, accountID) if err != nil { - return tongo.Transaction{}, err + return ton.Transaction{}, err } r, err := client.LiteServerGetOneTransaction(ctx, liteclient.LiteServerGetOneTransactionRequest{ Id: liteclient.BlockIDExt(blockId), @@ -556,42 +555,42 @@ func (c *Client) GetOneTransactionFromBlock( Lt: lt, }) if err != nil { - return tongo.Transaction{}, err + return ton.Transaction{}, err } if len(r.Transaction) == 0 { - return tongo.Transaction{}, fmt.Errorf("transaction not found") + return ton.Transaction{}, fmt.Errorf("transaction not found") } cells, err := boc.DeserializeBoc(r.Transaction) if err != nil { - return tongo.Transaction{}, err + return ton.Transaction{}, err } if len(cells) != 1 { - return tongo.Transaction{}, boc.ErrNotSingleRoot + return ton.Transaction{}, boc.ErrNotSingleRoot } var t tlb.Transaction err = tlb.Unmarshal(cells[0], &t) - return tongo.Transaction{Transaction: t, BlockID: r.Id.ToBlockIdExt()}, err + return ton.Transaction{Transaction: t, BlockID: r.Id.ToBlockIdExt()}, err } func (c *Client) GetTransactions( ctx context.Context, count uint32, - accountID tongo.AccountID, + accountID ton.AccountID, lt uint64, - hash tongo.Bits256, -) ([]tongo.Transaction, error) { + hash ton.Bits256, +) ([]ton.Transaction, error) { r, err := c.GetTransactionsRaw(ctx, count, accountID, lt, hash) if err != nil { return nil, err } if len(r.Transactions) == 0 { - return []tongo.Transaction{}, nil + return []ton.Transaction{}, nil } cells, err := boc.DeserializeBoc(r.Transactions) if err != nil { return nil, err } - var res []tongo.Transaction + var res []ton.Transaction for i, cell := range cells { var t tlb.Transaction cell.ResetCounters() @@ -599,7 +598,7 @@ func (c *Client) GetTransactions( if err != nil { return nil, err } - res = append(res, tongo.Transaction{ + res = append(res, ton.Transaction{ Transaction: t, BlockID: r.Ids[i].ToBlockIdExt(), }) @@ -607,7 +606,7 @@ func (c *Client) GetTransactions( return res, nil } -func (c *Client) GetTransactionsRaw(ctx context.Context, count uint32, accountID tongo.AccountID, lt uint64, hash tongo.Bits256) (liteclient.LiteServerTransactionListC, error) { +func (c *Client) GetTransactionsRaw(ctx context.Context, count uint32, accountID ton.AccountID, lt uint64, hash ton.Bits256) (liteclient.LiteServerTransactionListC, error) { client, _, err := c.pool.BestClientByAccountID(ctx, accountID) if err != nil { return liteclient.LiteServerTransactionListC{}, err @@ -624,18 +623,18 @@ func (c *Client) GetTransactionsRaw(ctx context.Context, count uint32, accountID return res, nil } -func (c *Client) GetLastTransactions(ctx context.Context, a tongo.AccountID, limit int) ([]tongo.Transaction, error) { +func (c *Client) GetLastTransactions(ctx context.Context, a ton.AccountID, limit int) ([]ton.Transaction, error) { state, err := c.GetAccountState(ctx, a) if err != nil { return nil, err } lastLt, lastHash := state.LastTransLt, state.LastTransHash - var res []tongo.Transaction + var res []ton.Transaction for { if lastLt == 0 { break } - txs, err := c.GetTransactions(ctx, 10, a, lastLt, tongo.Bits256(lastHash)) + txs, err := c.GetTransactions(ctx, 10, a, lastLt, ton.Bits256(lastHash)) if err != nil { if e, ok := err.(liteclient.LiteServerErrorC); ok && int32(e.Code) == -400 { // liteserver can store not full history. in that case it return error -400 for old transactions break @@ -658,7 +657,7 @@ func (c *Client) GetLastTransactions(ctx context.Context, a tongo.AccountID, lim func (c *Client) ListBlockTransactions( ctx context.Context, - blockID tongo.BlockIDExt, + blockID ton.BlockIDExt, mode, count uint32, after *liteclient.LiteServerTransactionId3C, ) ([]liteclient.LiteServerTransactionIdC, bool, error) { @@ -670,7 +669,7 @@ func (c *Client) ListBlockTransactions( return res.Ids, res.Incomplete, nil } -func (c *Client) ListBlockTransactionsRaw(ctx context.Context, blockID tongo.BlockIDExt, mode, count uint32, after *liteclient.LiteServerTransactionId3C) (liteclient.LiteServerBlockTransactionsC, error) { +func (c *Client) ListBlockTransactionsRaw(ctx context.Context, blockID ton.BlockIDExt, mode, count uint32, after *liteclient.LiteServerTransactionId3C) (liteclient.LiteServerBlockTransactionsC, error) { client, err := c.pool.BestClientByBlockID(ctx, blockID.BlockID) if err != nil { return liteclient.LiteServerBlockTransactionsC{}, err @@ -689,8 +688,8 @@ func (c *Client) ListBlockTransactionsRaw(ctx context.Context, blockID tongo.Blo func (c *Client) GetBlockProof( ctx context.Context, - knownBlock tongo.BlockIDExt, - targetBlock *tongo.BlockIDExt, + knownBlock ton.BlockIDExt, + targetBlock *ton.BlockIDExt, ) (liteclient.LiteServerPartialBlockProofC, error) { res, err := c.GetBlockProofRaw(ctx, knownBlock, targetBlock) if err != nil { @@ -700,7 +699,7 @@ func (c *Client) GetBlockProof( return res, nil } -func (c *Client) GetBlockProofRaw(ctx context.Context, knownBlock tongo.BlockIDExt, targetBlock *tongo.BlockIDExt) (liteclient.LiteServerPartialBlockProofC, error) { +func (c *Client) GetBlockProofRaw(ctx context.Context, knownBlock ton.BlockIDExt, targetBlock *ton.BlockIDExt) (liteclient.LiteServerPartialBlockProofC, error) { var ( err error client *liteclient.Client @@ -795,7 +794,7 @@ func decodeConfigParams(b []byte) (tlb.ConfigParams, error) { func (c *Client) GetValidatorStats( ctx context.Context, mode, limit uint32, - startAfter *tongo.Bits256, + startAfter *ton.Bits256, modifiedAfter *uint32, ) (*tlb.McStateExtra, error) { client, masterHead, err := c.pool.BestMasterchainClient(ctx) @@ -825,7 +824,7 @@ func (c *Client) GetValidatorStats( return nil, boc.ErrNotSingleRoot } var proof struct { - Proof tlb.MerkleProof[tlb.ShardState] // TODO: or tongo.ShardStateUnsplit + Proof tlb.MerkleProof[tlb.ShardState] // TODO: or ton.ShardStateUnsplit } err = tlb.Unmarshal(cells[0], &proof) if err != nil { @@ -836,7 +835,7 @@ func (c *Client) GetValidatorStats( return nil, fmt.Errorf("not implemented") } -func (c *Client) GetLibraries(ctx context.Context, libraryList []tongo.Bits256) (map[tongo.Bits256]*boc.Cell, error) { +func (c *Client) GetLibraries(ctx context.Context, libraryList []ton.Bits256) (map[ton.Bits256]*boc.Cell, error) { client, _, err := c.pool.BestMasterchainClient(ctx) if err != nil { return nil, err @@ -851,7 +850,7 @@ func (c *Client) GetLibraries(ctx context.Context, libraryList []tongo.Bits256) if err != nil { return nil, err } - libs := make(map[tongo.Bits256]*boc.Cell, len(r.Result)) + libs := make(map[ton.Bits256]*boc.Cell, len(r.Result)) for _, lib := range r.Result { data, err := boc.DeserializeBoc(lib.Data) if err != nil { @@ -860,7 +859,7 @@ func (c *Client) GetLibraries(ctx context.Context, libraryList []tongo.Bits256) if len(data) != 1 { return nil, fmt.Errorf("multiroot lib is not supported") } - libs[tongo.Bits256(lib.Hash)] = data[0] + libs[ton.Bits256(lib.Hash)] = data[0] } return libs, nil } diff --git a/liteapi/client_test.go b/liteapi/client_test.go index 191d2bd9..b4486f44 100644 --- a/liteapi/client_test.go +++ b/liteapi/client_test.go @@ -11,8 +11,8 @@ import ( "testing" "time" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" ) func TestNewClient_WithMaxConnectionsNumber(t *testing.T) { @@ -38,9 +38,9 @@ func TestGetTransactions(t *testing.T) { if err != nil { log.Fatalf("Unable to create tongo client: %v", err) } - accountId, _ := tongo.AccountIDFromRaw("-1:34517C7BDF5187C55AF4F8B61FDC321588C7AB768DEE24B006DF29106458D7CF") + accountId, _ := ton.AccountIDFromRaw("-1:34517C7BDF5187C55AF4F8B61FDC321588C7AB768DEE24B006DF29106458D7CF") var lt uint64 = 33973842000003 - hash := tongo.MustParseHash("8005AF92C0854B5A614427206673D120EA2914468C11C8F867F43740D6B4ACFB") + hash := ton.MustParseHash("8005AF92C0854B5A614427206673D120EA2914468C11C8F867F43740D6B4ACFB") tx, err := tongoClient.GetTransactions(context.Background(), 100, accountId, lt, hash) if err != nil { log.Fatalf("Get transaction error: %v", err) @@ -69,7 +69,7 @@ func TestRunSmcMethod(t *testing.T) { if err != nil { log.Fatalf("Unable to create tongo client: %v", err) } - accountId := tongo.MustParseAccountID("EQAs87W4yJHlF8mt29ocA4agnMrLsOP69jC1HPyBUjJay-7l") + accountId := ton.MustParseAccountID("EQAs87W4yJHlF8mt29ocA4agnMrLsOP69jC1HPyBUjJay-7l") _, _, err = tongoClient.RunSmcMethod(context.Background(), accountId, "seqno", tlb.VmStack{}) if err != nil { log.Fatalf("Run smc error: %v", err) @@ -106,15 +106,15 @@ func TestGetBlock(t *testing.T) { if err != nil { t.Fatal(err) } - block, err := api.GetBlock(context.TODO(), info.Last.ToBlockIdExt()) + b, err := api.GetBlock(context.TODO(), info.Last.ToBlockIdExt()) if err != nil { t.Fatal(err) } - p, err := tongo.GetParents(block.Info) + p, err := ton.GetParents(b.Info) if err != nil { t.Fatal(err) } - fmt.Printf("Block seqno: %v\n", block.Info.SeqNo) + fmt.Printf("Block seqno: %v\n", b.Info.SeqNo) fmt.Printf("1st parent block seqno: %v\n", p[0].Seqno) } @@ -149,7 +149,7 @@ func TestGetAccountState(t *testing.T) { } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { - accountID, err := tongo.AccountIDFromRaw(tt.accountID) + accountID, err := ton.AccountIDFromRaw(tt.accountID) if err != nil { t.Fatal("AccountIDFromRaw() failed: %w", err) } @@ -172,7 +172,7 @@ func TestLookupBlock(t *testing.T) { t.Fatal(err) } fmt.Printf("Current block seqno : %v\n", info.Last.Seqno) - blockID := tongo.BlockID{ + blockID := ton.BlockID{ Workchain: int32(info.Last.Workchain), Shard: info.Last.Shard, Seqno: info.Last.Seqno - 1, @@ -198,24 +198,24 @@ func TestGetOneTransaction(t *testing.T) { blockID := shards[0] var tx1 *tlb.Transaction for i := 0; i < 10; i++ { - block, err := tongoClient.GetBlock(ctx, blockID) + b, err := tongoClient.GetBlock(ctx, blockID) if err != nil { t.Fatal(err) } - if len(block.AllTransactions()) == 0 { - prev := block.Info.PrevRef.PrevBlkInfo.Prev - blockID = tongo.BlockIDExt{tongo.BlockID{ + if len(b.AllTransactions()) == 0 { + prev := b.Info.PrevRef.PrevBlkInfo.Prev + blockID = ton.BlockIDExt{ton.BlockID{ blockID.Workchain, blockID.Shard, prev.SeqNo, }, - tongo.Bits256(prev.RootHash), tongo.Bits256(prev.FileHash), + ton.Bits256(prev.RootHash), ton.Bits256(prev.FileHash), } continue } - tx1 = block.AllTransactions()[0] + tx1 = b.AllTransactions()[0] break } - tx2, err := tongoClient.GetOneTransactionFromBlock(context.Background(), tongo.AccountID{Workchain: blockID.Workchain, Address: tx1.AccountAddr}, blockID, tx1.Lt) + tx2, err := tongoClient.GetOneTransactionFromBlock(context.Background(), ton.AccountID{Workchain: blockID.Workchain, Address: tx1.AccountAddr}, blockID, tx1.Lt) if err != nil { log.Fatalf("Get transaction error: %v", err) } @@ -230,8 +230,8 @@ func TestGetLibraries(t *testing.T) { log.Fatalf("Unable to create tongo client: %v", err) } - hash := tongo.MustParseHash("587CC789EFF1C84F46EC3797E45FC809A14FF5AE24F1E0C7A6A99CC9DC9061FF") - libs, err := tongoClient.GetLibraries(context.Background(), []tongo.Bits256{hash}) + hash := ton.MustParseHash("587CC789EFF1C84F46EC3797E45FC809A14FF5AE24F1E0C7A6A99CC9DC9061FF") + libs, err := tongoClient.GetLibraries(context.Background(), []ton.Bits256{hash}) if err != nil { log.Fatalf("GetLibraries() failed: %v", err) } @@ -257,8 +257,8 @@ func TestGetJettonWallet(t *testing.T) { if err != nil { log.Fatalf("Unable to create tongo client: %v", err) } - master := tongo.MustParseAccountID("kQCKt2WPGX-fh0cIAz38Ljd_OKQjoZE_cqk7QrYGsNP6wfP0") - owner := tongo.MustParseAccountID("EQAs87W4yJHlF8mt29ocA4agnMrLsOP69jC1HPyBUjJay-7l") + master := ton.MustParseAccountID("kQCKt2WPGX-fh0cIAz38Ljd_OKQjoZE_cqk7QrYGsNP6wfP0") + owner := ton.MustParseAccountID("EQAs87W4yJHlF8mt29ocA4agnMrLsOP69jC1HPyBUjJay-7l") wallet, err := tongoClient.GetJettonWallet(context.Background(), master, owner) if err != nil { log.Fatalf("get jetton wallet error: %v", err) @@ -271,7 +271,7 @@ func TestGetJettonData(t *testing.T) { if err != nil { log.Fatalf("Unable to create tongo client: %v", err) } - master := tongo.MustParseAccountID("kQCKt2WPGX-fh0cIAz38Ljd_OKQjoZE_cqk7QrYGsNP6wfP0") + master := ton.MustParseAccountID("kQCKt2WPGX-fh0cIAz38Ljd_OKQjoZE_cqk7QrYGsNP6wfP0") meta, err := tongoClient.GetJettonData(context.Background(), master) if err != nil { log.Fatalf("get jetton decimals error: %v", err) @@ -284,7 +284,7 @@ func TestGetJettonBalance(t *testing.T) { if err != nil { log.Fatalf("Unable to create tongo client: %v", err) } - jettonWallet := tongo.MustParseAccountID("kQCOSEttz9aEGXkjd1h_NJsQqOca3T-Pld5zSIPHcYZIxsyf") + jettonWallet := ton.MustParseAccountID("kQCOSEttz9aEGXkjd1h_NJsQqOca3T-Pld5zSIPHcYZIxsyf") b, err := tongoClient.GetJettonBalance(context.Background(), jettonWallet) if err != nil { log.Fatalf("get jetton decimals error: %v", err) @@ -297,7 +297,7 @@ func TestDnsResolve(t *testing.T) { if err != nil { log.Fatalf("Unable to create tongo client: %v", err) } - root := tongo.MustParseAccountID("Ef_BimcWrQ5pmAWfRqfeVHUCNV8XgsLqeAMBivKryXrghFW3") + root := ton.MustParseAccountID("Ef_BimcWrQ5pmAWfRqfeVHUCNV8XgsLqeAMBivKryXrghFW3") m, _, err := tongoClient.DnsResolve(context.Background(), root, "ton\u0000alice\u0000", big.NewInt(0)) if err != nil { log.Fatalf("dns resolve error: %v", err) @@ -318,14 +318,14 @@ func TestGetRootDNS(t *testing.T) { } func TestClient_GetTransactionsForUnknownAccount(t *testing.T) { - var a tongo.AccountID + var a ton.AccountID rand.Read(a.Address[:]) client, err := NewClientWithDefaultTestnet() if err != nil { t.Error(err) } - txs, err := client.GetTransactions(context.Background(), 10, a, 0, tongo.Bits256{}) + txs, err := client.GetTransactions(context.Background(), 10, a, 0, ton.Bits256{}) if err != nil || len(txs) != 0 { t.Error(err, len(txs)) } @@ -338,7 +338,7 @@ func TestMappingTransactionsToBlocks(t *testing.T) { t.Fatal(err) } ctx := context.Background() - txs, err := c.GetLastTransactions(ctx, tongo.MustParseAccountID("0:408da3b28b6c065a593e10391269baaa9c5f8caebc0c69d9f0aabbab2a99256b"), limit) + txs, err := c.GetLastTransactions(ctx, ton.MustParseAccountID("0:408da3b28b6c065a593e10391269baaa9c5f8caebc0c69d9f0aabbab2a99256b"), limit) if err != nil { t.Fatal(err) } @@ -352,7 +352,7 @@ func TestMappingTransactionsToBlocks(t *testing.T) { } } - txsInBlockCache := make(map[tongo.Bits256][]tlb.Bits256) + txsInBlockCache := make(map[ton.Bits256][]tlb.Bits256) for _, tx := range txs { if _, ok := txsInBlockCache[tx.BlockID.RootHash]; !ok { block, err := c.GetBlock(ctx, tx.BlockID) diff --git a/liteapi/dns.go b/liteapi/dns.go index 29a005f4..92f5c9a6 100644 --- a/liteapi/dns.go +++ b/liteapi/dns.go @@ -3,14 +3,15 @@ package liteapi import ( "context" "fmt" - "github.com/tonkeeper/tongo" + "math/big" + "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" - "math/big" + "github.com/tonkeeper/tongo/ton" ) // DnsResolve is deprecated. please use github.com/tonkeeper/tongo/contract/dns -func (c *Client) DnsResolve(ctx context.Context, address tongo.AccountID, domain string, category *big.Int) (int, *boc.Cell, error) { +func (c *Client) DnsResolve(ctx context.Context, address ton.AccountID, domain string, category *big.Int) (int, *boc.Cell, error) { var params tlb.VmStack cell := boc.NewCell() err := cell.WriteBytes([]byte(domain)) @@ -49,23 +50,23 @@ func (c *Client) DnsResolve(ctx context.Context, address tongo.AccountID, domain return int(stack[0].VmStkTinyInt), &stack[1].VmStkCell.Value, err } -func (c *Client) GetRootDNS(ctx context.Context) (tongo.AccountID, error) { +func (c *Client) GetRootDNS(ctx context.Context) (ton.AccountID, error) { conf, err := c.GetConfigAll(ctx, 0) // TODO: check mode if err != nil { - return tongo.AccountID{}, err + return ton.AccountID{}, err } for i, k := range conf.Config.Keys() { if k == 4 { addr, err := conf.Config.Values()[i].Value.ReadBytes(32) if err != nil { - return tongo.AccountID{}, err + return ton.AccountID{}, err } - res := tongo.AccountID{ + res := ton.AccountID{ Workchain: -1, } copy(res.Address[:], addr) return res, nil } } - return tongo.AccountID{}, fmt.Errorf("config parameter not found") + return ton.AccountID{}, fmt.Errorf("config parameter not found") } diff --git a/liteapi/jetton.go b/liteapi/jetton.go index 58c9069a..809d117c 100644 --- a/liteapi/jetton.go +++ b/liteapi/jetton.go @@ -5,9 +5,9 @@ import ( "fmt" "math/big" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/tep64" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" ) var ( @@ -17,32 +17,32 @@ var ( // GetJettonWallet // TEP-74 Fungible tokens (Jettons) standard // https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md -func (c *Client) GetJettonWallet(ctx context.Context, master, owner tongo.AccountID) (tongo.AccountID, error) { +func (c *Client) GetJettonWallet(ctx context.Context, master, owner ton.AccountID) (ton.AccountID, error) { val, err := tlb.TlbStructToVmCellSlice(owner.ToMsgAddress()) if err != nil { - return tongo.AccountID{}, err + return ton.AccountID{}, err } errCode, stack, err := c.RunSmcMethod(ctx, master, "get_wallet_address", tlb.VmStack{val}) if err != nil { - return tongo.AccountID{}, err + return ton.AccountID{}, err } if errCode != 0 && errCode != 1 { - return tongo.AccountID{}, fmt.Errorf("method execution failed with code: %v", errCode) + return ton.AccountID{}, fmt.Errorf("method execution failed with code: %v", errCode) } if len(stack) != 1 || stack[0].SumType != "VmStkSlice" { - return tongo.AccountID{}, fmt.Errorf("invalid stack") + return ton.AccountID{}, fmt.Errorf("invalid stack") } var res tlb.MsgAddress err = stack[0].VmStkSlice.UnmarshalToTlbStruct(&res) if err != nil { - return tongo.AccountID{}, err + return ton.AccountID{}, err } - addr, err := tongo.AccountIDFromTlb(res) + addr, err := ton.AccountIDFromTlb(res) if err != nil { - return tongo.AccountID{}, err + return ton.AccountID{}, err } if addr == nil { - return tongo.AccountID{}, fmt.Errorf("addres none") + return ton.AccountID{}, fmt.Errorf("addres none") } return *addr, nil } @@ -50,33 +50,33 @@ func (c *Client) GetJettonWallet(ctx context.Context, master, owner tongo.Accoun // GetJettonData // TEP-74 Fungible tokens (Jettons) standard // https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md -func (c *Client) GetJettonData(ctx context.Context, master tongo.AccountID) (tongo.JettonMetadata, error) { +func (c *Client) GetJettonData(ctx context.Context, master ton.AccountID) (tep64.Metadata, error) { errCode, stack, err := c.RunSmcMethod(ctx, master, "get_jetton_data", tlb.VmStack{}) if err != nil { - return tongo.JettonMetadata{}, err + return tep64.Metadata{}, err } if errCode != 0 && errCode != 1 { - return tongo.JettonMetadata{}, fmt.Errorf("method execution failed with code: %v", errCode) + return tep64.Metadata{}, fmt.Errorf("method execution failed with code: %v", errCode) } if len(stack) != 5 || (stack[0].SumType != "VmStkTinyInt" && stack[0].SumType != "VmStkInt") || stack[1].SumType != "VmStkTinyInt" || stack[2].SumType != "VmStkSlice" || stack[3].SumType != "VmStkCell" || stack[4].SumType != "VmStkCell" { - return tongo.JettonMetadata{}, fmt.Errorf("invalid stack") + return tep64.Metadata{}, fmt.Errorf("invalid stack") } cell := &stack[3].VmStkCell.Value var content tlb.FullContent err = tlb.Unmarshal(cell, &content) if err != nil { - return tongo.JettonMetadata{}, err + return tep64.Metadata{}, err } if content.SumType != "Onchain" { - return tongo.JettonMetadata{}, ErrOnchainContentOnly + return tep64.Metadata{}, ErrOnchainContentOnly } meta, err := tep64.ConvertOnchainData(content) if err != nil { - return tongo.JettonMetadata{}, err + return tep64.Metadata{}, err } return meta, nil } @@ -84,7 +84,7 @@ func (c *Client) GetJettonData(ctx context.Context, master tongo.AccountID) (ton // GetJettonBalance // TEP-74 Fungible tokens (Jettons) standard // https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md -func (c *Client) GetJettonBalance(ctx context.Context, jettonWallet tongo.AccountID) (*big.Int, error) { +func (c *Client) GetJettonBalance(ctx context.Context, jettonWallet ton.AccountID) (*big.Int, error) { errCode, stack, err := c.RunSmcMethod(ctx, jettonWallet, "get_wallet_data", tlb.VmStack{}) if err != nil { return nil, err diff --git a/liteapi/pool/connection.go b/liteapi/pool/connection.go index 2c8d0482..0251c362 100644 --- a/liteapi/pool/connection.go +++ b/liteapi/pool/connection.go @@ -5,8 +5,8 @@ import ( "sync" "time" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/liteclient" + "github.com/tonkeeper/tongo/ton" ) type connection struct { @@ -18,17 +18,17 @@ type connection struct { mu sync.RWMutex // masterHead is the latest known masterchain head. - masterHead tongo.BlockIDExt + masterHead ton.BlockIDExt } type masterHeadUpdated struct { - Head tongo.BlockIDExt + Head ton.BlockIDExt Conn *connection } func (c *connection) Run(ctx context.Context) { for { - var head tongo.BlockIDExt + var head ton.BlockIDExt for { res, err := c.client.LiteServerGetMasterchainInfo(ctx) if err != nil { @@ -83,13 +83,13 @@ func (c *connection) Client() *liteclient.Client { return c.client } -func (c *connection) MasterHead() tongo.BlockIDExt { +func (c *connection) MasterHead() ton.BlockIDExt { c.mu.RLock() defer c.mu.RUnlock() return c.masterHead } -func (c *connection) SetMasterHead(head tongo.BlockIDExt) { +func (c *connection) SetMasterHead(head ton.BlockIDExt) { c.mu.Lock() defer c.mu.Unlock() if head.Seqno > c.masterHead.Seqno { diff --git a/liteapi/pool/failover_pool.go b/liteapi/pool/failover_pool.go index 7f07cba6..3847b697 100644 --- a/liteapi/pool/failover_pool.go +++ b/liteapi/pool/failover_pool.go @@ -6,8 +6,8 @@ import ( "sync" "time" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/liteclient" + "github.com/tonkeeper/tongo/ton" ) const ( @@ -32,15 +32,15 @@ type FailoverPool struct { mu sync.RWMutex bestConn conn waitListID uint64 - waitList map[uint64]chan tongo.BlockIDExt + waitList map[uint64]chan ton.BlockIDExt } // conn contains all methods needed by a pool. // used to implement tests. type conn interface { ID() int - MasterHead() tongo.BlockIDExt - SetMasterHead(tongo.BlockIDExt) + MasterHead() ton.BlockIDExt + SetMasterHead(ton.BlockIDExt) IsOK() bool Client() *liteclient.Client Run(ctx context.Context) @@ -66,7 +66,7 @@ func NewFailoverPool(clients []*liteclient.Client) *FailoverPool { conns: conns, updateBestInterval: updateBestConnectionInterval, bestConn: conns[0], - waitList: map[uint64]chan tongo.BlockIDExt{}, + waitList: map[uint64]chan ton.BlockIDExt{}, masterHeadUpdatedCh: masterHeadUpdatedCh, } } @@ -152,7 +152,7 @@ func (p *FailoverPool) BestMasterchainInfoClient() *MasterchainInfoClient { } // BestMasterchainClient returns a liteclient and its known masterchain head. -func (p *FailoverPool) BestMasterchainClient(ctx context.Context) (*liteclient.Client, tongo.BlockIDExt, error) { +func (p *FailoverPool) BestMasterchainClient(ctx context.Context) (*liteclient.Client, ton.BlockIDExt, error) { bestConnection := p.bestConnection() masterHead := bestConnection.MasterHead() if masterHead.Seqno > 0 { @@ -165,19 +165,19 @@ func (p *FailoverPool) BestMasterchainClient(ctx context.Context) (*liteclient.C select { case <-ctx.Done(): - return nil, tongo.BlockIDExt{}, ctx.Err() + return nil, ton.BlockIDExt{}, ctx.Err() case head := <-ch: return bestConnection.Client(), head, nil } } // BestClientByAccountID returns a liteclient and its known masterchain head. -func (p *FailoverPool) BestClientByAccountID(ctx context.Context, accountID tongo.AccountID) (*liteclient.Client, tongo.BlockIDExt, error) { +func (p *FailoverPool) BestClientByAccountID(ctx context.Context, accountID ton.AccountID) (*liteclient.Client, ton.BlockIDExt, error) { return p.BestMasterchainClient(ctx) } // BestClientByBlockID returns a liteclient and its known masterchain head. -func (p *FailoverPool) BestClientByBlockID(ctx context.Context, blockID tongo.BlockID) (*liteclient.Client, error) { +func (p *FailoverPool) BestClientByBlockID(ctx context.Context, blockID ton.BlockID) (*liteclient.Client, error) { server, _, err := p.BestMasterchainClient(ctx) return server, err } @@ -199,8 +199,8 @@ func (p *FailoverPool) notifySubscribers(update masterHeadUpdated) { } } -func (p *FailoverPool) subscribe(seqno uint32) (uint64, chan tongo.BlockIDExt) { - ch := make(chan tongo.BlockIDExt, 1) +func (p *FailoverPool) subscribe(seqno uint32) (uint64, chan ton.BlockIDExt) { + ch := make(chan ton.BlockIDExt, 1) p.mu.Lock() defer p.mu.Unlock() diff --git a/liteapi/pool/failover_pool_test.go b/liteapi/pool/failover_pool_test.go index 132da9a8..79acbe3e 100644 --- a/liteapi/pool/failover_pool_test.go +++ b/liteapi/pool/failover_pool_test.go @@ -5,8 +5,8 @@ import ( "testing" "time" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/liteclient" + "github.com/tonkeeper/tongo/ton" ) type mockConn struct { @@ -19,11 +19,11 @@ func (m *mockConn) ID() int { return 0 } -func (m *mockConn) MasterHead() tongo.BlockIDExt { - return tongo.BlockIDExt{BlockID: tongo.BlockID{Seqno: m.seqno}} +func (m *mockConn) MasterHead() ton.BlockIDExt { + return ton.BlockIDExt{BlockID: ton.BlockID{Seqno: m.seqno}} } -func (m *mockConn) SetMasterHead(ext tongo.BlockIDExt) { +func (m *mockConn) SetMasterHead(ext ton.BlockIDExt) { } func (m *mockConn) MasterSeqno() uint32 { diff --git a/liteapi/wallet.go b/liteapi/wallet.go index 65dbaa45..60e53e84 100644 --- a/liteapi/wallet.go +++ b/liteapi/wallet.go @@ -3,11 +3,12 @@ package liteapi import ( "context" "fmt" - "github.com/tonkeeper/tongo" + "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" ) -func (c *Client) GetSeqno(ctx context.Context, account tongo.AccountID) (uint32, error) { +func (c *Client) GetSeqno(ctx context.Context, account ton.AccountID) (uint32, error) { errCode, stack, err := c.RunSmcMethod(ctx, account, "seqno", tlb.VmStack{}) if err != nil { return 0, err diff --git a/liteclient/extensions.go b/liteclient/extensions.go index 820fdcb1..b66c382d 100644 --- a/liteclient/extensions.go +++ b/liteclient/extensions.go @@ -5,9 +5,10 @@ package liteclient import ( "bytes" "fmt" - "github.com/tonkeeper/tongo" - "github.com/tonkeeper/tongo/tl" "io" + + "github.com/tonkeeper/tongo/tl" + "github.com/tonkeeper/tongo/ton" ) var ( @@ -66,10 +67,10 @@ func (t *LiteServerSignatureSet) UnmarshalTL(r io.Reader) error { return nil } -func (t TonNodeBlockIdExtC) ToBlockIdExt() tongo.BlockIDExt { - res := tongo.BlockIDExt{ - RootHash: tongo.Bits256(t.RootHash), - FileHash: tongo.Bits256(t.FileHash), +func (t TonNodeBlockIdExtC) ToBlockIdExt() ton.BlockIDExt { + res := ton.BlockIDExt{ + RootHash: ton.Bits256(t.RootHash), + FileHash: ton.Bits256(t.FileHash), } res.Seqno = t.Seqno res.Shard = t.Shard @@ -77,14 +78,14 @@ func (t TonNodeBlockIdExtC) ToBlockIdExt() tongo.BlockIDExt { return res } -func AccountID(id tongo.AccountID) LiteServerAccountIdC { +func AccountID(id ton.AccountID) LiteServerAccountIdC { return LiteServerAccountIdC{ Workchain: uint32(id.Workchain), Id: id.Address, } } -func BlockIDExt(id tongo.BlockIDExt) TonNodeBlockIdExtC { +func BlockIDExt(id ton.BlockIDExt) TonNodeBlockIdExtC { return TonNodeBlockIdExtC{ Workchain: uint32(id.Workchain), Shard: id.Shard, diff --git a/liteclient/generated_test.go b/liteclient/generated_test.go index 51775318..62d25612 100644 --- a/liteclient/generated_test.go +++ b/liteclient/generated_test.go @@ -2,9 +2,10 @@ package liteclient import ( "bytes" - "github.com/tonkeeper/tongo/tl" "reflect" "testing" + + "github.com/tonkeeper/tongo/tl" ) var blk = TonNodeBlockIdExtC{ diff --git a/liteclient/keys.go b/liteclient/keys.go index bac54494..28842c32 100644 --- a/liteclient/keys.go +++ b/liteclient/keys.go @@ -3,6 +3,7 @@ package liteclient import ( "crypto/ed25519" "crypto/rand" + "github.com/oasisprotocol/curve25519-voi/curve" ed25519crv "github.com/oasisprotocol/curve25519-voi/primitives/ed25519" "github.com/oasisprotocol/curve25519-voi/primitives/x25519" diff --git a/shards.go b/shards.go index 98315f2c..db0e1a93 100644 --- a/shards.go +++ b/shards.go @@ -1,51 +1,15 @@ package tongo import ( - "encoding/binary" - "errors" - "math/bits" + "github.com/tonkeeper/tongo/ton" ) -type ShardID struct { - prefix int64 - mask int64 -} +type ShardID = ton.ShardID func ParseShardID(m int64) (ShardID, error) { - if m == 0 { - return ShardID{}, errors.New("at least one non-zero bit required in shard id") - } - trailingZeros := bits.TrailingZeros64(uint64(m)) - return ShardID{ - prefix: m ^ (1 << trailingZeros), - mask: -1 << (trailingZeros + 1), - }, nil + return ton.ParseShardID(m) } func MustParseShardID(m int64) ShardID { - s, err := ParseShardID(m) - if err != nil { - panic(err) - } - return s -} - -func (s ShardID) Encode() int64 { - return s.prefix | (1 << (bits.TrailingZeros64(uint64(s.mask)) - 1)) -} - -func (s ShardID) MatchAccountID(a AccountID) bool { - aPrefix := binary.BigEndian.Uint64(a.Address[:8]) - return (int64(aPrefix) & s.mask) == s.prefix -} - -func (s ShardID) MatchBlockID(block BlockID) bool { - sub, err := ParseShardID(int64(block.Shard)) - if err != nil { - return false - } - if bits.TrailingZeros64(uint64(s.mask)) < bits.TrailingZeros64(uint64(sub.mask)) { - return s.prefix&sub.mask == sub.prefix - } - return sub.prefix&s.mask == s.prefix + return ton.MustParseShardID(m) } diff --git a/tlb/benchmark_test.go b/tlb/benchmark_test.go index 82ef059a..088871ba 100644 --- a/tlb/benchmark_test.go +++ b/tlb/benchmark_test.go @@ -34,7 +34,7 @@ func Benchmark_Tlb_Unmarshal(b *testing.B) { } func Test_block(b *testing.T) { - data, err := os.ReadFile("../testdata/raw-13516764.bin") + data, err := os.ReadFile("../ton/testdata/raw-13516764.bin") if err != nil { b.Errorf("ReadFile() failed: %v", err) } diff --git a/ton/account.go b/ton/account.go new file mode 100644 index 00000000..430c393c --- /dev/null +++ b/ton/account.go @@ -0,0 +1,173 @@ +package ton + +import ( + "encoding/base64" + "encoding/binary" + "encoding/json" + "fmt" + "io" + "strings" + + "github.com/snksoft/crc" + "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/utils" +) + +type AccountID struct { + Workchain int32 + Address [32]byte +} + +func NewAccountId(id int32, addr [32]byte) *AccountID { + return &AccountID{Workchain: id, Address: addr} +} + +func (id AccountID) String() string { + return id.ToRaw() +} + +func (id AccountID) IsZero() bool { + for i := range id.Address { + if id.Address[i] != 0 { + return false + } + } + return true +} + +func (id AccountID) MarshalJSON() ([]byte, error) { + return json.Marshal(id.ToRaw()) +} + +func (id *AccountID) UnmarshalJSON(data []byte) error { + a, err := ParseAccountID(strings.Trim(string(data), "\"\n ")) + if err != nil { + return err + } + id.Workchain = a.Workchain + id.Address = a.Address + return nil +} + +func (id AccountID) ToRaw() string { + return fmt.Sprintf("%v:%x", id.Workchain, id.Address) +} + +func (id AccountID) ToHuman(bounce, testnet bool) string { + prefix := byte(0b00010001) + if testnet { + prefix |= 0b10000000 + } + if !bounce { + prefix |= 0b01000000 + } + buf := make([]byte, 36) + buf[0] = prefix + buf[1] = byte(id.Workchain) + copy(buf[2:34], id.Address[:]) + binary.BigEndian.PutUint16(buf[34:36], utils.Crc16(buf[:34])) + return base64.URLEncoding.EncodeToString(buf) +} + +func (id AccountID) MarshalTL() ([]byte, error) { + payload := make([]byte, 36) + binary.LittleEndian.PutUint32(payload[:4], uint32(id.Workchain)) + copy(payload[4:36], id.Address[:]) + return payload, nil +} + +func (id *AccountID) UnmarshalTL(r io.Reader) error { + var b [4]byte + _, err := io.ReadFull(r, b[:]) + if err != nil { + return err + } + id.Workchain = int32(binary.LittleEndian.Uint32(b[:])) + _, err = io.ReadFull(r, id.Address[:]) + return err +} + +func (id *AccountID) ToMsgAddress() tlb.MsgAddress { + if id == nil { + return tlb.MsgAddress{ + SumType: "AddrNone", + } + } + return tlb.MsgAddress{ + SumType: "AddrStd", + AddrStd: struct { + Anycast tlb.Maybe[tlb.Anycast] + WorkchainId int8 + Address tlb.Bits256 + }{ + WorkchainId: int8(id.Workchain), + Address: id.Address, + }, + } +} + +func AccountIDFromBase64Url(s string) (AccountID, error) { + var aa AccountID + b, err := base64.URLEncoding.DecodeString(s) + if err != nil { + return AccountID{}, err + } + if len(b) != 36 { + return AccountID{}, fmt.Errorf("invalid account 'user friendly' form length: %v", s) + } + checksum := uint64(binary.BigEndian.Uint16(b[34:36])) + if checksum != crc.CalculateCRC(crc.XMODEM, b[0:34]) { + return AccountID{}, fmt.Errorf("invalid checksum") + } + aa.Workchain = int32(int8(b[1])) + copy(aa.Address[:], b[2:34]) + return aa, nil +} + +func AccountIDFromRaw(s string) (AccountID, error) { + var ( + workchain int32 + address []byte + aa AccountID + ) + _, err := fmt.Sscanf(s, "%d:%x", &workchain, &address) + if err != nil { + return AccountID{}, err + } + if len(address) != 32 { + return AccountID{}, fmt.Errorf("address len must be 32 bytes") + } + aa.Workchain = workchain + copy(aa.Address[:], address) + return aa, nil +} + +func ParseAccountID(s string) (AccountID, error) { + aa, err := AccountIDFromRaw(s) + if err != nil { + aa, err = AccountIDFromBase64Url(s) + if err != nil { + return AccountID{}, err + } + } + return aa, nil +} + +func MustParseAccountID(s string) AccountID { + aa, err := ParseAccountID(s) + if err != nil { + panic(err) + } + return aa +} + +// TODO: replace pointer with nullable type +func AccountIDFromTlb(a tlb.MsgAddress) (*AccountID, error) { + switch a.SumType { + case "AddrNone", "AddrExtern": //todo: make something with external addresses + return nil, nil + case "AddrStd": + return &AccountID{Workchain: int32(a.AddrStd.WorkchainId), Address: a.AddrStd.Address}, nil + } + return nil, fmt.Errorf("can not convert not std address to AccountId") +} diff --git a/account_test.go b/ton/account_test.go similarity index 98% rename from account_test.go rename to ton/account_test.go index 88a065f3..c759b83c 100644 --- a/account_test.go +++ b/ton/account_test.go @@ -1,4 +1,4 @@ -package tongo +package ton import ( "encoding/json" diff --git a/ton/address.go b/ton/address.go new file mode 100644 index 00000000..965326e5 --- /dev/null +++ b/ton/address.go @@ -0,0 +1,15 @@ +package ton + +import ( + "github.com/tonkeeper/tongo/tlb" +) + +// Address identifies an account in the TON network. +// Comparing to AccountID which is a low-level identifier of a smart contract, +// Address is a high-level abstraction containing additional information besides AccountID, +// which is useful for building more advanced workflows. +type Address struct { + ID AccountID + Bounce bool + StateInit *tlb.StateInit +} diff --git a/ton/bits.go b/ton/bits.go new file mode 100644 index 00000000..7b238b92 --- /dev/null +++ b/ton/bits.go @@ -0,0 +1,131 @@ +package ton + +import ( + "bytes" + "database/sql/driver" + "encoding/base64" + "encoding/hex" + "errors" + "fmt" + "strings" + + "github.com/tonkeeper/tongo/tlb" +) + +type Bits256 tlb.Bits256 + +func (h Bits256) Base64() string { + return base64.StdEncoding.EncodeToString(h[:]) +} + +func (h Bits256) Hex() string { + return fmt.Sprintf("%x", h[:]) +} +func (h *Bits256) FromBase64(s string) error { + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + return err + } + if len(b) != 32 { + return errors.New("invalid hash length") + } + copy(h[:], b) + return nil +} + +func (h *Bits256) FromBase64URL(s string) error { + b, err := base64.URLEncoding.DecodeString(s) + if err != nil { + return err + } + if len(b) != 32 { + return errors.New("invalid hash length") + } + copy(h[:], b) + return nil +} + +func (h *Bits256) FromHex(s string) error { + if strings.HasPrefix(s, "0x") { + s = s[2:] + } + b, err := hex.DecodeString(s) + if err != nil { + return err + } + if len(b) != 32 { + return errors.New("invalid hash length") + } + copy(h[:], b) + return nil +} + +func (h *Bits256) FromUnknownString(s string) error { + err := h.FromBase64(s) + if err == nil { + return nil + } + err = h.FromBase64URL(s) + if err == nil { + return nil + } + err = h.FromHex(s) + if err == nil { + return nil + } + return err +} + +func (h *Bits256) FromBytes(b []byte) error { + if len(b) != 32 { + return fmt.Errorf("can't scan []byte of len %d into Bits256, want %d", len(b), 32) + } + copy(h[:], b) + return nil +} + +func ParseHash(s string) (Bits256, error) { + var h Bits256 + err := h.FromUnknownString(s) + return h, err +} + +func MustParseHash(s string) Bits256 { + h, err := ParseHash(s) + if err != nil { + panic(err) + } + return h +} + +// Scan implements Scanner for database/sql. +func (h *Bits256) Scan(src interface{}) error { + srcB, ok := src.([]byte) + if !ok { + return fmt.Errorf("can't scan %T into Bits256", src) + } + if len(srcB) != 32 { + return fmt.Errorf("can't scan []byte of len %d into Bits256, want %d", len(srcB), 32) + } + copy(h[:], srcB) + return nil +} + +// Value implements valuer for database/sql. +func (h Bits256) Value() (driver.Value, error) { + return h[:], nil +} + +func (b Bits256) MarshalJSON() ([]byte, error) { + return fmt.Appendf(nil, "\"%x\"", b), nil +} + +func (b *Bits256) UnmarshalJSON(buf []byte) error { + var sl []byte + _, err := fmt.Fscanf(bytes.NewReader(buf), "\"%x\"", &sl) + if len(sl) != 32 { + return fmt.Errorf("can't parse 256bits %v", string(buf)) + } + copy(b[:], sl) + return err +} diff --git a/bits_test.go b/ton/bits_test.go similarity index 97% rename from bits_test.go rename to ton/bits_test.go index 224cd2b6..608845dc 100644 --- a/bits_test.go +++ b/ton/bits_test.go @@ -1,4 +1,4 @@ -package tongo +package ton import ( "crypto/sha256" diff --git a/ton/block.go b/ton/block.go new file mode 100644 index 00000000..6edc346d --- /dev/null +++ b/ton/block.go @@ -0,0 +1,240 @@ +package ton + +import ( + "encoding/binary" + "fmt" + + "github.com/tonkeeper/tongo/boc" + "github.com/tonkeeper/tongo/tlb" +) + +type BlockID struct { + Workchain int32 + Shard uint64 + Seqno uint32 +} + +type BlockIDExt struct { + BlockID + RootHash Bits256 + FileHash Bits256 +} + +func (id BlockIDExt) MarshalTL() ([]byte, error) { + payload := make([]byte, 80) + binary.LittleEndian.PutUint32(payload[:4], uint32(id.Workchain)) + binary.LittleEndian.PutUint64(payload[4:12], id.Shard) + binary.LittleEndian.PutUint32(payload[12:16], id.Seqno) + copy(payload[16:48], id.RootHash[:]) + copy(payload[48:80], id.FileHash[:]) + return payload, nil +} + +func (id *BlockIDExt) UnmarshalTL(data []byte) error { + if len(data) != 80 { + return fmt.Errorf("invalid data length") + } + id.Workchain = int32(binary.LittleEndian.Uint32(data[:4])) + id.Shard = binary.LittleEndian.Uint64(data[4:12]) + id.Seqno = binary.LittleEndian.Uint32(data[12:16]) + copy(id.RootHash[:], data[16:48]) + copy(id.FileHash[:], data[48:80]) + return nil +} + +func NewTonBlockId(fileHash, rootHash Bits256, seqno uint32, shard uint64, workchain int32) *BlockIDExt { + return &BlockIDExt{ + BlockID: BlockID{ + Workchain: workchain, + Shard: shard, + Seqno: seqno, + }, + FileHash: fileHash, + RootHash: rootHash, + } +} + +func (id BlockIDExt) String() string { + return fmt.Sprintf("(%d,%x,%d,%x,%x)", id.Workchain, id.Shard, id.Seqno, id.RootHash, id.FileHash) +} +func (id BlockID) String() string { + return fmt.Sprintf("(%d,%x,%d)", id.Workchain, id.Shard, id.Seqno) +} + +func getParents(blkPrevInfo tlb.BlkPrevInfo, afterSplit, afterMerge bool, shard uint64, workchain int32) ([]BlockIDExt, error) { + var parents []BlockIDExt + if !afterMerge { + if blkPrevInfo.SumType != "PrevBlkInfo" { + return nil, fmt.Errorf("two parent blocks may be only after merge") + } + blockID := BlockIDExt{ + BlockID: BlockID{ + Workchain: workchain, + Seqno: blkPrevInfo.PrevBlkInfo.Prev.SeqNo, + }, + FileHash: Bits256(blkPrevInfo.PrevBlkInfo.Prev.FileHash), + RootHash: Bits256(blkPrevInfo.PrevBlkInfo.Prev.RootHash), + } + if afterSplit { + blockID.Shard = shardParent(shard) + return []BlockIDExt{blockID}, nil + } + blockID.Shard = shard + return []BlockIDExt{blockID}, nil + } + + if blkPrevInfo.SumType != "PrevBlksInfo" { + return nil, fmt.Errorf("two parent blocks must be after merge") + } + + parents = append(parents, BlockIDExt{ + BlockID: BlockID{ + Seqno: blkPrevInfo.PrevBlksInfo.Prev1.SeqNo, + Shard: shardChild(shard, true), + Workchain: workchain, + }, + FileHash: Bits256(blkPrevInfo.PrevBlksInfo.Prev1.FileHash), + RootHash: Bits256(blkPrevInfo.PrevBlksInfo.Prev1.RootHash), + }) + + parents = append(parents, BlockIDExt{ + FileHash: Bits256(blkPrevInfo.PrevBlksInfo.Prev2.FileHash), + RootHash: Bits256(blkPrevInfo.PrevBlksInfo.Prev2.RootHash), + BlockID: BlockID{ + Seqno: blkPrevInfo.PrevBlksInfo.Prev2.SeqNo, + Shard: shardChild(shard, false), + Workchain: workchain, + }, + }) + + return parents, nil +} + +// td::uint64 x = td::lower_bit64(shard) >> 1; +// return left ? shard - x : shard + x; +func shardChild(shard uint64, left bool) uint64 { + x := (shard & (^shard + 1)) >> 1 + if left { + return shard - x + } + return shard + x +} + +// td::uint64 x = td::lower_bit64(shard); +// return (shard - x) | (x << 1); +func shardParent(shard uint64) uint64 { + x := shard & (^shard + 1) + return (shard - x) | (x << 1) +} + +func convertShardIdent(si tlb.ShardIdent) (workchain int32, shard uint64) { + shard = si.ShardPrefix + pow2 := uint64(1) << (63 - si.ShardPfxBits) + shard |= pow2 + return si.WorkchainID, shard +} + +func GetParents(i tlb.BlockInfo) ([]BlockIDExt, error) { + workchain, shard := convertShardIdent(i.Shard) + return getParents(i.PrevRef, i.AfterSplit, i.AfterMerge, shard, workchain) +} + +func ToBlockId(s tlb.ShardDesc, workchain int32) BlockIDExt { + if s.SumType == "Old" { + return BlockIDExt{ + BlockID: BlockID{ + Workchain: workchain, + Shard: uint64(s.Old.NextValidatorShard), + Seqno: s.Old.SeqNo, + }, + RootHash: Bits256(s.Old.RootHash), + FileHash: Bits256(s.Old.FileHash), + } + } else { + return BlockIDExt{ + BlockID: BlockID{ + Workchain: workchain, + Shard: uint64(s.New.NextValidatorShard), + Seqno: s.New.SeqNo, + }, + RootHash: Bits256(s.New.RootHash), + FileHash: Bits256(s.New.FileHash), + } + } +} + +func CreateExternalMessage(address AccountID, body *boc.Cell, init *tlb.StateInit, importFee tlb.Grams) (tlb.Message, error) { + // TODO: add either selection algorithm + var msg = tlb.Message{ + Info: tlb.CommonMsgInfo{ + SumType: "ExtInMsgInfo", + ExtInMsgInfo: &struct { + Src tlb.MsgAddress + Dest tlb.MsgAddress + ImportFee tlb.Grams + }{ + Src: (*AccountID)(nil).ToMsgAddress(), + Dest: address.ToMsgAddress(), + ImportFee: importFee, + }, + }, + Body: tlb.EitherRef[tlb.Any]{ + IsRight: true, + Value: tlb.Any(*body), + }, + } + if init != nil { + msg.Init.Exists = true + msg.Init.Value.IsRight = true + msg.Init.Value.Value = *init + } + return msg, nil +} + +// ShardIDs returns a list of IDs of shard blocks this block refers to. +func ShardIDs(blk *tlb.Block) []BlockIDExt { + if !blk.Extra.Custom.Exists { + return nil + } + items := blk.Extra.Custom.Value.Value.ShardHashes.Items() + shardsCount := 0 + for _, item := range items { + for _, x := range item.Value.Value.BinTree.Values { + if x.SeqNo() == 0 { + continue + } + shardsCount += 1 + } + } + if shardsCount == 0 { + return nil + } + shards := make([]BlockIDExt, 0, shardsCount) + for _, item := range items { + for _, shardDesc := range item.Value.Value.BinTree.Values { + if shardDesc.SeqNo() == 0 { + continue + } + shards = append(shards, ToBlockId(shardDesc, int32(item.Key))) + } + } + return shards +} + +// ParseBlockID tries to construct BlockID from the given string. +func ParseBlockID(s string) (BlockID, error) { + var id BlockID + _, err := fmt.Sscanf(s, "(%d,%x,%d)", &id.Workchain, &id.Shard, &id.Seqno) + if err != nil { + return BlockID{}, err + } + return id, nil +} + +func MustParseBlockID(s string) BlockID { + id, err := ParseBlockID(s) + if err != nil { + panic(err) + } + return id +} diff --git a/block_test.go b/ton/block_test.go similarity index 99% rename from block_test.go rename to ton/block_test.go index 8d10e1df..a7e3dbb4 100644 --- a/block_test.go +++ b/ton/block_test.go @@ -1,4 +1,4 @@ -package tongo +package ton import ( "os" diff --git a/grams.go b/ton/grams.go similarity index 85% rename from grams.go rename to ton/grams.go index 92aa7db9..3da69bea 100644 --- a/grams.go +++ b/ton/grams.go @@ -1,4 +1,4 @@ -package tongo +package ton import "github.com/tonkeeper/tongo/tlb" diff --git a/ton/shards.go b/ton/shards.go new file mode 100644 index 00000000..f5693bfe --- /dev/null +++ b/ton/shards.go @@ -0,0 +1,51 @@ +package ton + +import ( + "encoding/binary" + "errors" + "math/bits" +) + +type ShardID struct { + prefix int64 + mask int64 +} + +func ParseShardID(m int64) (ShardID, error) { + if m == 0 { + return ShardID{}, errors.New("at least one non-zero bit required in shard id") + } + trailingZeros := bits.TrailingZeros64(uint64(m)) + return ShardID{ + prefix: m ^ (1 << trailingZeros), + mask: -1 << (trailingZeros + 1), + }, nil +} + +func MustParseShardID(m int64) ShardID { + s, err := ParseShardID(m) + if err != nil { + panic(err) + } + return s +} + +func (s ShardID) Encode() int64 { + return s.prefix | (1 << (bits.TrailingZeros64(uint64(s.mask)) - 1)) +} + +func (s ShardID) MatchAccountID(a AccountID) bool { + aPrefix := binary.BigEndian.Uint64(a.Address[:8]) + return (int64(aPrefix) & s.mask) == s.prefix +} + +func (s ShardID) MatchBlockID(block BlockID) bool { + sub, err := ParseShardID(int64(block.Shard)) + if err != nil { + return false + } + if bits.TrailingZeros64(uint64(s.mask)) < bits.TrailingZeros64(uint64(sub.mask)) { + return s.prefix&sub.mask == sub.prefix + } + return sub.prefix&s.mask == s.prefix +} diff --git a/shards_test.go b/ton/shards_test.go similarity index 99% rename from shards_test.go rename to ton/shards_test.go index c3f576d7..cc155f40 100644 --- a/shards_test.go +++ b/ton/shards_test.go @@ -1,4 +1,4 @@ -package tongo +package ton import ( "testing" diff --git a/testdata/raw-13516764.bin b/ton/testdata/raw-13516764.bin similarity index 100% rename from testdata/raw-13516764.bin rename to ton/testdata/raw-13516764.bin diff --git a/ton/transactions.go b/ton/transactions.go new file mode 100644 index 00000000..10eab8af --- /dev/null +++ b/ton/transactions.go @@ -0,0 +1,8 @@ +package ton + +import "github.com/tonkeeper/tongo/tlb" + +type Transaction struct { + tlb.Transaction + BlockID BlockIDExt +} diff --git a/tonconnect/server.go b/tonconnect/server.go index c2833a7c..834c8fb2 100644 --- a/tonconnect/server.go +++ b/tonconnect/server.go @@ -17,10 +17,10 @@ import ( "strings" "time" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/abi" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/wallet" ) @@ -153,7 +153,7 @@ func (s *Server) CheckProof(ctx context.Context, tp *Proof) (bool, ed25519.Publi return false, nil, fmt.Errorf("proof has been expired") } - accountID, err := tongo.ParseAccountID(tp.Address) + accountID, err := ton.ParseAccountID(tp.Address) if err != nil { return false, nil, err } @@ -244,7 +244,7 @@ func convertTonProofMessage(tp *Proof) (*parsedMessage, error) { }, nil } -func (s *Server) getWalletPubKey(ctx context.Context, address tongo.AccountID) (ed25519.PublicKey, error) { +func (s *Server) getWalletPubKey(ctx context.Context, address ton.AccountID) (ed25519.PublicKey, error) { _, result, err := abi.GetPublicKey(ctx, s.executor, address) if err != nil { return nil, err @@ -344,7 +344,7 @@ func ParseStateInit(stateInit string) ([]byte, error) { return pubKey[:], nil } -func compareStateInitWithAddress(a tongo.AccountID, stateInit string) (bool, error) { +func compareStateInitWithAddress(a ton.AccountID, stateInit string) (bool, error) { cells, err := boc.DeserializeBocBase64(stateInit) if err != nil || len(cells) != 1 { return false, err diff --git a/tontest/helpers.go b/tontest/helpers.go index 1ac95e82..82cfd221 100644 --- a/tontest/helpers.go +++ b/tontest/helpers.go @@ -5,9 +5,9 @@ import ( "fmt" "time" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" ) type accountBuilder struct { @@ -18,7 +18,7 @@ type accountBuilder struct { lastLT *uint64 lastHash *tlb.Bits256 workchain *int32 - address *tongo.AccountID + address *ton.AccountID frozenHash *tlb.Bits256 } @@ -26,7 +26,7 @@ func Account() accountBuilder { return accountBuilder{} } -func (b accountBuilder) Address(a tongo.AccountID) accountBuilder { +func (b accountBuilder) Address(a ton.AccountID) accountBuilder { b.address = &a return b } @@ -80,7 +80,7 @@ func (b accountBuilder) ShardAccount() (tlb.ShardAccount, error) { }, }, nil } - var address *tongo.AccountID + var address *ton.AccountID if b.address != nil { address = b.address } @@ -184,8 +184,8 @@ const Internal MsgType = 1 type messageBuilder struct { msgType MsgType - to *tongo.AccountID - from tongo.AccountID + to *ton.AccountID + from ton.AccountID value tlb.Grams bounce bool bounced bool @@ -196,11 +196,11 @@ func NewMessage() messageBuilder { return messageBuilder{} } -func (b messageBuilder) To(a tongo.AccountID) messageBuilder { +func (b messageBuilder) To(a ton.AccountID) messageBuilder { b.to = &a return b } -func (b messageBuilder) Internal(from tongo.AccountID, value tlb.Grams) messageBuilder { +func (b messageBuilder) Internal(from ton.AccountID, value tlb.Grams) messageBuilder { b.msgType = Internal b.value = value b.from = from @@ -286,7 +286,7 @@ func (b messageBuilder) Message() (tlb.Message, error) { return m, nil } -func initToAddress(workchain int32, code, data *boc.Cell) (*tongo.AccountID, error) { +func initToAddress(workchain int32, code, data *boc.Cell) (*ton.AccountID, error) { initState := boc.NewCell() s := tlb.StateInit{} if code != nil { @@ -306,7 +306,7 @@ func initToAddress(workchain int32, code, data *boc.Cell) (*tongo.AccountID, err if err != nil { return nil, err } - a := tongo.AccountID{Workchain: workchain} + a := ton.AccountID{Workchain: workchain} copy(a.Address[:], hash) code.ResetCounters() data.ResetCounters() diff --git a/transactions.go b/transactions.go index f474cafd..ee69525b 100644 --- a/transactions.go +++ b/transactions.go @@ -1,8 +1,7 @@ package tongo -import "github.com/tonkeeper/tongo/tlb" +import ( + "github.com/tonkeeper/tongo/ton" +) -type Transaction struct { - tlb.Transaction - BlockID BlockIDExt -} +type Transaction = ton.Transaction diff --git a/tvm/tvmExecutor.go b/tvm/tvmExecutor.go index 1dd30cfe..06f2dd08 100644 --- a/tvm/tvmExecutor.go +++ b/tvm/tvmExecutor.go @@ -17,9 +17,9 @@ import ( "time" "unsafe" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/txemulator" "github.com/tonkeeper/tongo/utils" ) @@ -234,12 +234,12 @@ type result struct { GasUsed string `json:"gas_used"` } -func (e *Emulator) RunSmcMethod(ctx context.Context, accountId tongo.AccountID, method string, params tlb.VmStack) (uint32, tlb.VmStack, error) { +func (e *Emulator) RunSmcMethod(ctx context.Context, accountId ton.AccountID, method string, params tlb.VmStack) (uint32, tlb.VmStack, error) { methodID := utils.MethodIdFromName(method) return e.RunSmcMethodByID(ctx, accountId, methodID, params) } -func (e *Emulator) RunSmcMethodByID(ctx context.Context, accountId tongo.AccountID, methodID int, params tlb.VmStack) (uint32, tlb.VmStack, error) { +func (e *Emulator) RunSmcMethodByID(ctx context.Context, accountId ton.AccountID, methodID int, params tlb.VmStack) (uint32, tlb.VmStack, error) { if !e.lazyC7 { err := e.setC7(accountId.ToRaw(), uint32(time.Now().Unix())) if err != nil { diff --git a/tvm/tvmExecutor_test.go b/tvm/tvmExecutor_test.go index fff4abca..3533a00e 100644 --- a/tvm/tvmExecutor_test.go +++ b/tvm/tvmExecutor_test.go @@ -6,9 +6,9 @@ import ( "math/big" "testing" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/txemulator" ) @@ -19,7 +19,7 @@ func TestRunGetMethod(t *testing.T) { dataCell, _ := boc.DeserializeBocBase64("te6ccsECEgEAAmcAAAAALwAzAFcAbwB8AIEAhgCLAPsBeQG8AfcCAgIHAicCOAI/A1OAH+KPIWfXRAHhzc8BIGKAZ7CGFDhMB09Wc+npbBemPgcgAAAAAAAAaBABBBECAAIDAEQBaHR0cHM6Ly9sb3Rvbi5mdW4vY29sbGVjdGlvbi5qc29uACxodHRwczovL2xvdG9uLmZ1bi9uZnQvART/APSkE/S88sgLBQIBYgYQAgLOBw0CASAIDALXDIhxwCSXwPg0NMDAXGwkl8D4PpA+kAx+gAxcdch+gAx+gAw8AIEs44UMGwiNFIyxwXy4ZUB+kDUMBAj8APgBtMf0z+CEF/MPRRSMLqOhzIQN14yQBPgMDQ0NTWCEC/LJqISuuMCXwSED/LwgCQsB9lE1xwXy4ZH6QCHwAfpA0gAx+gCCCvrwgBuhIZRTFaCh3iLXCwHDACCSBqGRNuIgwv/y4ZIhjj6CEAUTjZHIUAnPFlALzxZxJEkUVEagcIAQyMsFUAfPFlAF+gIVy2oSyx/LPyJus5RYzxcBkTLiAckB+wAQR5QQKjdb4goAggKONSbwAYIQ1TJ22xA3RABtcXCAEMjLBVAHzxZQBfoCFctqEssfyz8ibrOUWM8XAZEy4gHJAfsAkzAyNOJVAvADAHJwghCLdxc1BcjL/1AEzxYQJIBAcIAQyMsFUAfPFlAF+gIVy2oSyx/LPyJus5RYzxcBkTLiAckB+wAAET6RDBwuvLhTYAIBIA4PADs7UTQ0z/6QCDXScIAmn8B+kDUMBAkECPgMHBZbW2AAHQDyMs/WM8WAc8WzMntVIAAJoR+f4AUASwBkA+iAH+KPIWfXRAHhzc8BIGKAZ7CGFDhMB09Wc+npbBemPgcw9Pr6lQ==") config, _ := boc.DeserializeBocBase64(mainnetConfig) index := tlb.Int257(*big.NewInt(100)) - account, _ := tongo.AccountIDFromRaw("0:4ccba08d80193c3eb4f92cd8cf10bc425ff2d705a552aad6f3453a141e51b7b7") + account, _ := ton.AccountIDFromRaw("0:4ccba08d80193c3eb4f92cd8cf10bc425ff2d705a552aad6f3453a141e51b7b7") val := tlb.VmStackValue{ SumType: "VmStkInt", @@ -52,7 +52,7 @@ func TestRunGetMethod_MYADDR(t *testing.T) { codeCell, _ := boc.DeserializeBocHex("b5ee9c72410106010026000114ff00f4a413f4bcf2c80b01020120020302014804050004f2300004d0300009a17d69f0510464af6e") dataCell, _ := boc.DeserializeBocHex("b5ee9c7241010101002a0000500000000000000000febdbf007927e5f1e9aad18bb45255281f521861e27272b2c9e383ad48c1b1333c77b344") config, _ := boc.DeserializeBocBase64(mainnetConfig) - account, _ := tongo.AccountIDFromRaw("0:665f75889f630daa0ac81044ece59f42fdcde17d3df692adb9a73cae0959b9e0") + account, _ := ton.AccountIDFromRaw("0:665f75889f630daa0ac81044ece59f42fdcde17d3df692adb9a73cae0959b9e0") emulator, err := NewEmulator(codeCell[0], dataCell[0], config[0], WithLazyC7Optimization()) if err != nil { @@ -77,7 +77,7 @@ func TestRunGetMethod_MYADDR(t *testing.T) { if err != nil { t.Fatal(err) } - accountID, err := tongo.AccountIDFromTlb(addr) + accountID, err := ton.AccountIDFromTlb(addr) if err != nil { t.Fatal(err) } @@ -88,14 +88,14 @@ func TestEmulator_WithLibraries(t *testing.T) { codeCell, _ := boc.DeserializeSinglRootBase64("te6ccgEBAQEAIwAIQgJYfMeJ7/HIT0bsN5fkX8gJoU/1riTx4MemqZzJ3JBh/w==") dataCell, _ := boc.DeserializeSinglRootBase64("te6ccgEBAQEAJgAASAAAAAFADM/69gpLOqEdnlFlgw9dtQ9qcJxeaDf/99Bpg9BMSw==") config, _ := boc.DeserializeSinglRootBase64(mainnetConfig) - account, _ := tongo.AccountIDFromRaw("EQDa2R3ST5ep0u9dXCtgO-1Mp0J_hlZuZFCvofjLaVSY3tlD") + account, _ := ton.AccountIDFromRaw("EQDa2R3ST5ep0u9dXCtgO-1Mp0J_hlZuZFCvofjLaVSY3tlD") - hash := tongo.MustParseHash("587CC789EFF1C84F46EC3797E45FC809A14FF5AE24F1E0C7A6A99CC9DC9061FF") + hash := ton.MustParseHash("587CC789EFF1C84F46EC3797E45FC809A14FF5AE24F1E0C7A6A99CC9DC9061FF") cell, err := boc.DeserializeSinglRootBase64("te6ccgEBAQEAXwAAuv8AIN0gggFMl7ohggEznLqxnHGw7UTQ0x/XC//jBOCk8mCBAgDXGCDXCx/tRNDTH9P/0VESuvKhIvkBVBBE+RDyovgAAdMfMSDXSpbTB9QC+wDe0aTIyx/L/8ntVA==") if err != nil { t.Fatalf("boc.DeserializeSinglRootBase64() failed: %v", err) } - base64libs, err := txemulator.LibrariesToBase64(map[tongo.Bits256]*boc.Cell{hash: cell}) + base64libs, err := txemulator.LibrariesToBase64(map[ton.Bits256]*boc.Cell{hash: cell}) if err != nil { t.Fatalf("LibrariesToBase64() failed: %v", err) } diff --git a/txemulator/trace.go b/txemulator/trace.go index 9b555761..9e113355 100644 --- a/txemulator/trace.go +++ b/txemulator/trace.go @@ -5,15 +5,15 @@ import ( "fmt" "time" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/liteapi" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" ) type Tracer struct { e *Emulator - currentShardAccount map[tongo.AccountID]tlb.ShardAccount + currentShardAccount map[ton.AccountID]tlb.ShardAccount blockchain accountGetter counter int limit int @@ -30,12 +30,12 @@ type TraceOptions struct { blockchain accountGetter time int64 checkSignature bool - predefinedAccounts map[tongo.AccountID]tlb.ShardAccount + predefinedAccounts map[ton.AccountID]tlb.ShardAccount } type accountGetter interface { - GetAccountState(ctx context.Context, a tongo.AccountID) (tlb.ShardAccount, error) - GetLibraries(ctx context.Context, libraries []tongo.Bits256) (map[tongo.Bits256]*boc.Cell, error) + GetAccountState(ctx context.Context, a ton.AccountID) (tlb.ShardAccount, error) + GetLibraries(ctx context.Context, libraries []ton.Bits256) (map[ton.Bits256]*boc.Cell, error) } func WithConfig(c *boc.Cell) TraceOption { @@ -67,7 +67,7 @@ func WithTime(t int64) TraceOption { } } -func WithAccountsMap(m map[tongo.AccountID]tlb.ShardAccount) TraceOption { +func WithAccountsMap(m map[ton.AccountID]tlb.ShardAccount) TraceOption { return func(o *TraceOptions) error { o.predefinedAccounts = m return nil @@ -76,7 +76,7 @@ func WithAccountsMap(m map[tongo.AccountID]tlb.ShardAccount) TraceOption { func WithAccounts(accounts ...tlb.ShardAccount) TraceOption { return func(o *TraceOptions) error { for i := range accounts { - a, err := tongo.AccountIDFromTlb(accounts[i].Account.Account.Addr) + a, err := ton.AccountIDFromTlb(accounts[i].Account.Account.Addr) if err != nil { return err } @@ -117,7 +117,7 @@ func NewTraceBuilder(options ...TraceOption) (*Tracer, error) { blockchain: nil, time: time.Now().Unix(), checkSignature: false, - predefinedAccounts: make(map[tongo.AccountID]tlb.ShardAccount), + predefinedAccounts: make(map[ton.AccountID]tlb.ShardAccount), } for _, o := range options { err := o(&option) @@ -189,7 +189,7 @@ func (t *Tracer) Run(ctx context.Context, message tlb.Message) (*TxTree, error) default: return nil, fmt.Errorf("can't emulate message with type %v", message.Info.SumType) } - accountAddr, err := tongo.AccountIDFromTlb(a) + accountAddr, err := ton.AccountIDFromTlb(a) if err != nil { return nil, err } @@ -203,7 +203,7 @@ func (t *Tracer) Run(ctx context.Context, message tlb.Message) (*TxTree, error) return nil, err } } - publicLibs := map[tongo.Bits256]*boc.Cell{} + publicLibs := map[ton.Bits256]*boc.Cell{} for _, code := range []*boc.Cell{accountCode(state), msgStateInitCode(message)} { if code == nil { continue @@ -259,6 +259,6 @@ func (t *Tracer) Run(ctx context.Context, message tlb.Message) (*TxTree, error) return tree, err } -func (t *Tracer) FinalStates() map[tongo.AccountID]tlb.ShardAccount { +func (t *Tracer) FinalStates() map[ton.AccountID]tlb.ShardAccount { return t.currentShardAccount } diff --git a/txemulator/trace_test.go b/txemulator/trace_test.go index 17269fb7..57bc4358 100644 --- a/txemulator/trace_test.go +++ b/txemulator/trace_test.go @@ -4,10 +4,10 @@ import ( "context" "testing" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/liteapi" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/tontest" "github.com/tonkeeper/tongo/wallet" ) @@ -27,16 +27,16 @@ func TestSimpleEmulation(t *testing.T) { w, err := wallet.DefaultWalletFromSeed(SEED, client) seqno := uint32(0) - mock, messages := wallet.NewMockBlockchain(seqno, tontest.Account().Address(tongo.AccountID{}).State(tlb.AccountActive).MustShardAccount()) + mock, messages := wallet.NewMockBlockchain(seqno, tontest.Account().Address(ton.AccountID{}).State(tlb.AccountActive).MustShardAccount()) w, err = wallet.DefaultWalletFromSeed(SEED, mock) if err != nil { t.Fatal(err) } err = w.Send(ctx, wallet.SimpleTransfer{ - Amount: tongo.OneTON / 10, + Amount: ton.OneTON / 10, Address: w.GetAddress(), }, wallet.SimpleTransfer{ - Amount: tongo.OneTON / 10, + Amount: ton.OneTON / 10, Address: w.GetAddress(), }) if err != nil { @@ -59,7 +59,7 @@ func TestSimpleEmulation(t *testing.T) { if len(tree.Children) != 2 { t.Fatal(len(tree.Children)) } - if tree.Children[0].TX.Msgs.InMsg.Value.Value.Info.IntMsgInfo.Value.Grams != tongo.OneTON/10 { + if tree.Children[0].TX.Msgs.InMsg.Value.Value.Info.IntMsgInfo.Value.Grams != ton.OneTON/10 { t.Fatal("invalid amount") } } diff --git a/utils/generator.go b/utils/generator.go index a75324af..36d88fe0 100644 --- a/utils/generator.go +++ b/utils/generator.go @@ -1,10 +1,11 @@ package utils import ( + "strings" + "golang.org/x/exp/constraints" "golang.org/x/exp/maps" "golang.org/x/exp/slices" - "strings" ) func ToCamelCase(s string) string { diff --git a/wallet/mock.go b/wallet/mock.go index fdeb4550..035ffa1c 100644 --- a/wallet/mock.go +++ b/wallet/mock.go @@ -3,8 +3,8 @@ package wallet import ( "context" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" ) // SimpleMockBlockchain @@ -25,7 +25,7 @@ func NewMockBlockchain(seqno uint32, state tlb.ShardAccount) (*SimpleMockBlockch }, c } -func (b *SimpleMockBlockchain) GetSeqno(ctx context.Context, account tongo.AccountID) (uint32, error) { +func (b *SimpleMockBlockchain) GetSeqno(ctx context.Context, account ton.AccountID) (uint32, error) { return b.seqno, nil } @@ -40,6 +40,6 @@ func (b *SimpleMockBlockchain) SendMessage(ctx context.Context, payload []byte) return 0, nil } -func (b *SimpleMockBlockchain) GetAccountState(ctx context.Context, accountID tongo.AccountID) (tlb.ShardAccount, error) { +func (b *SimpleMockBlockchain) GetAccountState(ctx context.Context, accountID ton.AccountID) (tlb.ShardAccount, error) { return b.state, nil } diff --git a/wallet/models.go b/wallet/models.go index a918392c..903f8838 100644 --- a/wallet/models.go +++ b/wallet/models.go @@ -6,9 +6,9 @@ import ( "fmt" "time" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" ) type Version int @@ -66,9 +66,9 @@ func init() { } type blockchain interface { - GetSeqno(ctx context.Context, account tongo.AccountID) (uint32, error) + GetSeqno(ctx context.Context, account ton.AccountID) (uint32, error) SendMessage(ctx context.Context, payload []byte) (uint32, error) - GetAccountState(ctx context.Context, accountID tongo.AccountID) (tlb.ShardAccount, error) + GetAccountState(ctx context.Context, accountID ton.AccountID) (tlb.ShardAccount, error) } func GetCodeByVer(ver Version) *boc.Cell { @@ -112,7 +112,7 @@ func (v Version) ToString() string { type Wallet struct { key ed25519.PrivateKey - address tongo.AccountID + address ton.AccountID ver Version subWalletId uint32 blockchain blockchain @@ -120,7 +120,7 @@ type Wallet struct { // GetAddress returns current wallet address but you can also call function GenerateWalletAddress // which returns same address but doesn't require blockchain connection for calling -func (w *Wallet) GetAddress() tongo.AccountID { +func (w *Wallet) GetAddress() ton.AccountID { return w.address } @@ -156,7 +156,7 @@ type Sendable interface { type SimpleTransfer struct { Amount tlb.Grams - Address tongo.AccountID + Address ton.AccountID Comment string Bounceable bool } @@ -180,7 +180,7 @@ func (m SimpleTransfer) ToInternal() (message tlb.Message, mode uint8, err error }{ IhrDisabled: true, Bounce: m.Bounceable, - Src: (*tongo.AccountID)(nil).ToMsgAddress(), + Src: (*ton.AccountID)(nil).ToMsgAddress(), Dest: m.Address.ToMsgAddress(), } info.IntMsgInfo.Value.Grams = m.Amount @@ -203,7 +203,7 @@ func (m SimpleTransfer) ToInternal() (message tlb.Message, mode uint8, err error type Message struct { Amount tlb.Grams - Address tongo.AccountID + Address ton.AccountID Body *boc.Cell Code *boc.Cell Data *boc.Cell @@ -230,7 +230,7 @@ func (m Message) ToInternal() (message tlb.Message, mode uint8, err error) { }{ IhrDisabled: true, Bounce: m.Bounce, - Src: (*tongo.AccountID)(nil).ToMsgAddress(), + Src: (*ton.AccountID)(nil).ToMsgAddress(), Dest: m.Address.ToMsgAddress(), } info.IntMsgInfo.Value.Grams = m.Amount diff --git a/wallet/seed.go b/wallet/seed.go index 97ca4591..ef70fa77 100644 --- a/wallet/seed.go +++ b/wallet/seed.go @@ -7,9 +7,11 @@ import ( "crypto/sha512" "errors" "fmt" - "github.com/tonkeeper/tongo/boc" - "golang.org/x/crypto/pbkdf2" "strings" + + "golang.org/x/crypto/pbkdf2" + + "github.com/tonkeeper/tongo/boc" ) func RandomSeed() string { diff --git a/wallet/wallet.go b/wallet/wallet.go index 49b9c9c8..4f791917 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -3,13 +3,14 @@ package wallet import ( "context" "crypto/ed25519" + "errors" "fmt" "math/rand" "time" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" ) func DefaultWalletFromSeed(seed string, blockchain blockchain) (Wallet, error) { @@ -55,26 +56,26 @@ func GenerateWalletAddress( ver Version, workchain int, subWalletId *int, -) (tongo.AccountID, error) { +) (ton.AccountID, error) { state, err := GenerateStateInit(key, ver, workchain, subWalletId) if err != nil { - return tongo.AccountID{}, fmt.Errorf("can not generate wallet state: %v", err) + return ton.AccountID{}, fmt.Errorf("can not generate wallet state: %v", err) } stateCell := boc.NewCell() err = tlb.Marshal(stateCell, state) if err != nil { - return tongo.AccountID{}, fmt.Errorf("can not marshal wallet state: %v", err) + return ton.AccountID{}, fmt.Errorf("can not marshal wallet state: %v", err) } h, err := stateCell.Hash() if err != nil { - return tongo.AccountID{}, err + return ton.AccountID{}, err } var hash tlb.Bits256 copy(hash[:], h[:]) if err != nil { - return tongo.AccountID{}, fmt.Errorf("can not calculate state init hash: %v", err) + return ton.AccountID{}, fmt.Errorf("can not calculate state init hash: %v", err) } - return tongo.AccountID{Workchain: int32(workchain), Address: hash}, nil + return ton.AccountID{Workchain: int32(workchain), Address: hash}, nil } func GenerateStateInit( @@ -145,13 +146,13 @@ func (w *Wallet) RawSendV2( internalMessages []RawMessage, init *tlb.StateInit, waitingConfirmation time.Duration, -) (tongo.Bits256, error) { +) (ton.Bits256, error) { if w.blockchain == nil { - return tongo.Bits256{}, tongo.BlockchainInterfaceIsNil + return ton.Bits256{}, errors.New("blockchain interface is nil") } err := checkMessagesLimit(len(internalMessages), w.ver) if err != nil { - return tongo.Bits256{}, err + return ton.Bits256{}, nil } bodyCell := boc.NewCell() switch w.ver { @@ -181,15 +182,15 @@ func (w *Wallet) RawSendV2( } err = tlb.Marshal(bodyCell, body) default: - return tongo.Bits256{}, fmt.Errorf("message body generation for this wallet is not supported: %v", err) + return ton.Bits256{}, fmt.Errorf("message body generation for this wallet is not supported: %v", err) } if err != nil { - return tongo.Bits256{}, fmt.Errorf("can not marshal wallet message body: %v", err) + return ton.Bits256{}, fmt.Errorf("can not marshal wallet message body: %v", err) } signBytes, err := bodyCell.Sign(w.key) if err != nil { - return tongo.Bits256{}, fmt.Errorf("can not sign wallet message body: %v", err) + return ton.Bits256{}, fmt.Errorf("can not sign wallet message body: %v", err) } bits512 := tlb.Bits512{} copy(bits512[:], signBytes[:]) @@ -199,24 +200,24 @@ func (w *Wallet) RawSendV2( } signedBodyCell := boc.NewCell() if err = tlb.Marshal(signedBodyCell, signedBody); err != nil { - return tongo.Bits256{}, fmt.Errorf("can not marshal signed body: %v", err) + return ton.Bits256{}, fmt.Errorf("can not marshal signed body: %v", err) } - extMsg, err := tongo.CreateExternalMessage(w.address, signedBodyCell, init, 0) + extMsg, err := ton.CreateExternalMessage(w.address, signedBodyCell, init, 0) if err != nil { - return tongo.Bits256{}, fmt.Errorf("can not create external message: %v", err) + return ton.Bits256{}, fmt.Errorf("can not create external message: %v", err) } extMsgCell := boc.NewCell() err = tlb.Marshal(extMsgCell, extMsg) if err != nil { - return tongo.Bits256{}, fmt.Errorf("can not marshal wallet external message: %v", err) + return ton.Bits256{}, fmt.Errorf("can not marshal wallet external message: %v", err) } msgHash, err := extMsgCell.Hash256() if err != nil { - return tongo.Bits256{}, fmt.Errorf("can not create external message: %v", err) + return ton.Bits256{}, fmt.Errorf("can not create external message: %v", err) } payload, err := extMsgCell.ToBocCustom(false, false, false, 0) if err != nil { - return tongo.Bits256{}, fmt.Errorf("can not serialize external message cell: %v", err) + return ton.Bits256{}, fmt.Errorf("can not serialize external message cell: %v", err) } t := time.Now() _, err = w.blockchain.SendMessage(ctx, payload) // TODO: add result code check @@ -282,9 +283,9 @@ func (w *Wallet) SendV2( ctx context.Context, waitingConfirmation time.Duration, messages ...Sendable, -) (tongo.Bits256, error) { +) (ton.Bits256, error) { if w.blockchain == nil { - return tongo.Bits256{}, tongo.BlockchainInterfaceIsNil + return ton.Bits256{}, errors.New("blockchain interface is nil") } var init *tlb.StateInit @@ -292,7 +293,7 @@ func (w *Wallet) SendV2( state, err := w.blockchain.GetAccountState(ctx, w.GetAddress()) if err != nil { - return tongo.Bits256{}, err + return ton.Bits256{}, err } requireInit := false switch w.ver { @@ -303,7 +304,7 @@ func (w *Wallet) SendV2( if state.Account.Status() == tlb.AccountActive { seqno, err = w.blockchain.GetSeqno(ctx, w.address) if err != nil { - return tongo.Bits256{}, err + return ton.Bits256{}, err } } requireInit = seqno == 0 @@ -311,7 +312,7 @@ func (w *Wallet) SendV2( if requireInit { i, err := w.getInit() if err != nil { - return tongo.Bits256{}, err + return ton.Bits256{}, err } init = &i } @@ -319,12 +320,12 @@ func (w *Wallet) SendV2( for _, m := range messages { intMsg, mode, err := m.ToInternal() if err != nil { - return tongo.Bits256{}, err + return ton.Bits256{}, err } cell := boc.NewCell() err = tlb.Marshal(cell, intMsg) if err != nil { - return tongo.Bits256{}, err + return ton.Bits256{}, err } msgArray = append(msgArray, RawMessage{Message: cell, Mode: mode}) } @@ -345,7 +346,7 @@ func (w *Wallet) Send(ctx context.Context, messages ...Sendable) error { // Gets actual TON balance for wallet func (w *Wallet) GetBalance(ctx context.Context) (uint64, error) { if w.blockchain == nil { - return 0, tongo.BlockchainInterfaceIsNil + return 0, errors.New("blockchain interface is nil") } state, err := w.blockchain.GetAccountState(ctx, w.address) if err != nil { diff --git a/wallet/wallet_test.go b/wallet/wallet_test.go index 8690ba6d..a4caa9bc 100644 --- a/wallet/wallet_test.go +++ b/wallet/wallet_test.go @@ -9,10 +9,10 @@ import ( "log" "testing" - "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/liteapi" "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/tontest" ) @@ -92,7 +92,7 @@ func TestLongCommentSerialization(t *testing.T) { func TestSimpleSend(t *testing.T) { t.Skip() - recipientAddr, _ := tongo.AccountIDFromRaw("0:507dea7d606f22d9e85678d3eede39bbe133a868d2a0e3e07f5502cb70b8a512") + recipientAddr, _ := ton.AccountIDFromRaw("0:507dea7d606f22d9e85678d3eede39bbe133a868d2a0e3e07f5502cb70b8a512") client, err := liteapi.NewClientWithDefaultTestnet() if err != nil { log.Fatalf("Unable to create tongo client: %v", err) @@ -123,8 +123,8 @@ func TestGetSeqno(t *testing.T) { } func TestMockBlockchain(t *testing.T) { - recipientAddr, _ := tongo.AccountIDFromRaw("0:507dea7d606f22d9e85678d3eede39bbe133a868d2a0e3e07f5502cb70b8a512") - client, c := NewMockBlockchain(1, tontest.Account().Balance(10000).Address(tongo.AccountID{}).MustShardAccount()) + recipientAddr, _ := ton.AccountIDFromRaw("0:507dea7d606f22d9e85678d3eede39bbe133a868d2a0e3e07f5502cb70b8a512") + client, c := NewMockBlockchain(1, tontest.Account().Balance(10000).Address(ton.AccountID{}).MustShardAccount()) w := initDefaultWallet(client) tonTransfer := SimpleTransfer{ Amount: 10000,