From ac9bf0dd3c9c60bcd527d83cbe31b047cd0f0ace Mon Sep 17 00:00:00 2001 From: "aleksej.paschenko" Date: Wed, 1 May 2024 10:19:09 +0300 Subject: [PATCH 1/4] Use go1.21 in tests --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 4aa8d846..00a7bee1 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -17,7 +17,7 @@ jobs: - name: Go Version uses: actions/setup-go@v3 with: - go-version: '1.19' + go-version: '1.21' - name: test env: LD_LIBRARY_PATH: ${{ github.workspace }}/libs From 549b5d2462db1dac1c0f0a568603bb9795bfef74 Mon Sep 17 00:00:00 2001 From: "aleksej.paschenko" Date: Wed, 1 May 2024 10:29:33 +0300 Subject: [PATCH 2/4] Fix gram tests --- abi/generated_test.go | 40 +++++++++++++++++++++------------------- abi/schemas/gram.xml | 2 +- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/abi/generated_test.go b/abi/generated_test.go index a1c236a8..f8e75bac 100644 --- a/abi/generated_test.go +++ b/abi/generated_test.go @@ -461,6 +461,27 @@ func TestMessageDecoder(t *testing.T) { interfaces []ContractInterface wantValidate func(t *testing.T, value any) }{ + { + name: "gram miner - submit proof of work", + interfaces: []ContractInterface{GramMiner}, + wantOpName: "GramSubmitProofOfWork", + boc: "te6ccgEBAQEAewAA8k1pbmUAZh5n6Ko92S+6JcXv0vZh3JgmUoAzO2R8CeNp7hvCAYZUe9AHyiw3HOIN5fq3UWUTxJ2NzkQQ8n/18ag79sePGkYAAACknATyivxe2NapVEVFPsjSyiw3HOIN5fq3UWUTxJ2NzkQQ8n/18ag79sePGkYAAAA=", + wantValidate: func(t *testing.T, value any) { + seed := big.Int{} + seed.SetString("218803489964525407889229111495606847698", 10) + body := GramSubmitProofOfWorkMsgBody{ + Flags: 0, + Expire: 1713268712, + Whom: mustToBits256("aa3dd92fba25c5efd2f661dc98265280333b647c09e369ee1bc20186547bd007"), + Rdata1: mustToBits256("ca2c371ce20de5fab7516513c49d8dce4410f27ff5f1a83bf6c78f1a46000000"), + Rseed: tlb.Uint128(seed), + Rdata2: mustToBits256("ca2c371ce20de5fab7516513c49d8dce4410f27ff5f1a83bf6c78f1a46000000"), + } + if !reflect.DeepEqual(value, body) { + t.Fatalf("got: %v, want: %v", value, body) + } + }, + }, { name: "jetton burn notification", boc: "te6ccgEBAQEASAAAi3vdl952mKNkA9fVjzGM4ygA2ZpktQsYby0n9cV5VWOFINBjScIU2HdondFsK3lDpEB64AEuSPMwX2JvQ+QTUtfXxYKTyMA=", @@ -1075,25 +1096,6 @@ func TestDecodeExternalIn(t *testing.T) { wantOpName string wantValue func() any }{ - { - name: "gram miner - submit proof of work", - interfaces: []ContractInterface{GramMiner}, - wantOpName: "GramSubmitProofOfWork", - boc: "te6ccgEBAQEAewAA8k1pbmUAZh5n6Ko92S+6JcXv0vZh3JgmUoAzO2R8CeNp7hvCAYZUe9AHyiw3HOIN5fq3UWUTxJ2NzkQQ8n/18ag79sePGkYAAACknATyivxe2NapVEVFPsjSyiw3HOIN5fq3UWUTxJ2NzkQQ8n/18ag79sePGkYAAAA=", - wantValue: func() any { - seed := big.Int{} - seed.SetString("218803489964525407889229111495606847698", 10) - body := GramSubmitProofOfWorkMsgBody{ - Flags: 0, - Expire: 1713268712, - Whom: mustToBits256("aa3dd92fba25c5efd2f661dc98265280333b647c09e369ee1bc20186547bd007"), - Rdata1: mustToBits256("ca2c371ce20de5fab7516513c49d8dce4410f27ff5f1a83bf6c78f1a46000000"), - Rseed: tlb.Uint128(seed), - Rdata2: mustToBits256("ca2c371ce20de5fab7516513c49d8dce4410f27ff5f1a83bf6c78f1a46000000"), - } - return body - }, - }, { name: "highload wallet v3 - jetton transfer", interfaces: []ContractInterface{WalletHighloadV3R1}, diff --git a/abi/schemas/gram.xml b/abi/schemas/gram.xml index d34d9776..653712bb 100644 --- a/abi/schemas/gram.xml +++ b/abi/schemas/gram.xml @@ -15,6 +15,6 @@ - payload#4d696e65 flags:uint8 expire:uint32 whom:bits256 rdata1:bits256 rseed:uint128 rdata2:bits256 = ExternalMsgBody; + payload#4d696e65 flags:uint8 expire:uint32 whom:bits256 rdata1:bits256 rseed:uint128 rdata2:bits256 = InternalMsgBody; From 6ecb456305bfa649fa9833e02b16ecebc24e39cb Mon Sep 17 00:00:00 2001 From: "aleksej.paschenko" Date: Wed, 1 May 2024 10:36:56 +0300 Subject: [PATCH 3/4] Fix mistakenly broken test --- liteclient/client_test.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/liteclient/client_test.go b/liteclient/client_test.go index 73f22e62..2c5b7078 100644 --- a/liteclient/client_test.go +++ b/liteclient/client_test.go @@ -7,7 +7,6 @@ import ( "fmt" "os" "testing" - "time" "github.com/tonkeeper/tongo/config" ) @@ -54,14 +53,11 @@ func TestGeneratedMethod(t *testing.T) { } client := NewClient(c) - for { - resp, err := client.LiteServerGetMasterchainInfo(context.Background()) - if err != nil { - panic(err) - } - fmt.Printf("Last seqno: %d\n", resp.Last.Seqno) - time.Sleep(1 * time.Second) + resp, err := client.LiteServerGetMasterchainInfo(context.Background()) + if err != nil { + panic(err) } + fmt.Printf("Last seqno: %d\n", resp.Last.Seqno) } func TestGeneratedMethod2(t *testing.T) { From b01a2ca513d42a059078d741db3d81ca7fe6b573 Mon Sep 17 00:00:00 2001 From: "aleksej.paschenko" Date: Wed, 1 May 2024 10:16:40 +0300 Subject: [PATCH 4/4] Add wallet v5 support --- tlb/generator.go | 2 +- tlb/integers.go | 30 +++++++++ wallet/messages.go | 142 +++++++++++++++++++++++++++++++++++++++- wallet/messages_test.go | 87 ++++++++++++++++++++++++ wallet/models.go | 4 +- 5 files changed, 262 insertions(+), 3 deletions(-) diff --git a/tlb/generator.go b/tlb/generator.go index 16fd5584..fcb68cb9 100644 --- a/tlb/generator.go +++ b/tlb/generator.go @@ -9,7 +9,7 @@ import ( "github.com/tonkeeper/tongo/tlb/parser" ) -var bitsSizes = []int{96, 256, 264, 320, 352, 512} +var bitsSizes = []int{80, 96, 256, 264, 320, 352, 512} var intSizes = []int{128, 256, 257} func main() { diff --git a/tlb/integers.go b/tlb/integers.go index 43e328e9..67cc2b9f 100644 --- a/tlb/integers.go +++ b/tlb/integers.go @@ -6100,6 +6100,36 @@ func (u *Int257) UnmarshalJSON(p []byte) error { return nil } +type Bits80 [10]byte + +func (u Bits80) FixedSize() int { + return 80 +} + +func (u Bits80) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf("\"%x\"", u[:])), nil +} + +func (u *Bits80) UnmarshalJSON(b []byte) error { + bs, err := hex.DecodeString(strings.Trim(string(b), "\"")) + if err != nil { + return err + } + if len(bs) != 10 { + return fmt.Errorf("can't parse Bits80 %v", string(b)) + } + copy(u[:], bs) + return nil +} + +func (u Bits80) Equal(other any) bool { + otherBits, ok := other.(Bits80) + if !ok { + return false + } + return u == otherBits +} + type Bits96 [12]byte func (u Bits96) FixedSize() int { diff --git a/wallet/messages.go b/wallet/messages.go index e04ce99e..cef828a7 100644 --- a/wallet/messages.go +++ b/wallet/messages.go @@ -2,12 +2,15 @@ package wallet import ( "crypto/ed25519" + "errors" "fmt" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" ) +var ErrBadSignature = errors.New("failed to verify msg signature") + type MessageV3 struct { SubWalletId uint32 ValidUntil uint32 @@ -24,6 +27,39 @@ type MessageV4 struct { RawMessages PayloadV1toV4 } +type SendMessageAction struct { + Magic tlb.Magic `tlb:"#0ec3c86d"` + Mode uint8 + Msg *boc.Cell `tlb:"^"` +} + +type SendMessageList struct { + Actions []SendMessageAction +} + +// MessageV5 is a message format used by wallet v5. +type MessageV5 struct { + tlb.SumType + // Sint is an internal message authenticated by a signature. + Sint struct { + SubWalletId tlb.Bits80 + ValidUntil uint32 + Seqno uint32 + Op bool + Signature tlb.Bits512 + Actions SendMessageList `tlb:"^"` + } `tlbSumType:"#73696e74"` + // Sign is an external message authenticated by a signature. + Sign struct { + SubWalletId tlb.Bits80 + ValidUntil uint32 + Seqno uint32 + Op bool + Signature tlb.Bits512 + Actions SendMessageList `tlb:"^"` + } `tlbSumType:"#7369676e"` +} + type HighloadV2Message struct { SubWalletId uint32 BoundedQueryID uint64 @@ -56,7 +92,7 @@ func (body *SignedMsgBody) Verify(publicKey ed25519.PublicKey) error { if ed25519.Verify(publicKey, hash, body.Sign[:]) { return nil } - return fmt.Errorf("failed to verify msg signature") + return ErrBadSignature } func extractSignedMsgBody(msg *boc.Cell) (*SignedMsgBody, error) { @@ -72,6 +108,19 @@ func extractSignedMsgBody(msg *boc.Cell) (*SignedMsgBody, error) { return &msgBody, nil } +func DecodeMessageV5(msg *boc.Cell) (*MessageV5, error) { + var m tlb.Message + if err := tlb.Unmarshal(msg, &m); err != nil { + return nil, err + } + var msgv5 MessageV5 + bodyCell := boc.Cell(m.Body.Value) + if err := tlb.Unmarshal(&bodyCell, &msgv5); err != nil { + return nil, err + } + return &msgv5, nil +} + func DecodeMessageV4(msg *boc.Cell) (*MessageV4, error) { signedMsgBody, err := extractSignedMsgBody(msg) if err != nil { @@ -126,6 +175,12 @@ func decodeHighloadV2Message(body *SignedMsgBody) (*HighloadV2Message, error) { // ExtractRawMessages extracts a list of RawMessages from an external message. func ExtractRawMessages(ver Version, msg *boc.Cell) ([]RawMessage, error) { switch ver { + case V5R1: + v5, err := DecodeMessageV5(msg) + if err != nil { + return nil, err + } + return v5.RawMessages(), nil case V4R1, V4R2: v4, err := DecodeMessageV4(msg) if err != nil { @@ -259,3 +314,88 @@ func (p *PayloadHighload) UnmarshalTLB(c *boc.Cell, decoder *tlb.Decoder) error *p = rawMessages return nil } + +func (l *SendMessageList) UnmarshalTLB(c *boc.Cell, decoder *tlb.Decoder) error { + var actions []SendMessageAction + for { + switch c.BitsAvailableForRead() { + case 0: + l.Actions = actions + return nil + case 40: + next, err := c.NextRef() + if err != nil { + return err + } + var action SendMessageAction + if err := decoder.Unmarshal(c, &action); err != nil { + return err + } + actions = append(actions, action) + c = next + default: + return fmt.Errorf("unexpected bits available: %v", c.BitsAvailableForRead()) + } + } +} + +func MessageV5VerifySignature(msgBody boc.Cell, publicKey ed25519.PublicKey) error { + totalBits := msgBody.BitsAvailableForRead() + if totalBits < 512 { + return fmt.Errorf("not enough bits in the cell") + } + bits, err := msgBody.ReadBits(totalBits - 512) + if err != nil { + return err + } + signature, err := msgBody.ReadBytes(64) + if err != nil { + return err + } + msgCopy := boc.NewCell() + if err := msgCopy.WriteBitString(bits); err != nil { + return err + } + for i := 0; i < msgBody.RefsSize(); i++ { + ref, err := msgBody.NextRef() + if err != nil { + return err + } + if err := msgCopy.AddRef(ref); err != nil { + return err + } + } + hash, err := msgCopy.Hash() + if err != nil { + return err + } + if ed25519.Verify(publicKey, hash, signature) { + return nil + } + return ErrBadSignature +} + +func (m *MessageV5) RawMessages() []RawMessage { + switch m.SumType { + case "Sint": + msgs := make([]RawMessage, 0, len(m.Sint.Actions.Actions)) + for _, action := range m.Sint.Actions.Actions { + msgs = append(msgs, RawMessage{ + Message: action.Msg, + Mode: action.Mode, + }) + } + return msgs + case "Sign": + msgs := make([]RawMessage, 0, len(m.Sign.Actions.Actions)) + for _, action := range m.Sign.Actions.Actions { + msgs = append(msgs, RawMessage{ + Message: action.Msg, + Mode: action.Mode, + }) + } + return msgs + default: + return nil + } +} diff --git a/wallet/messages_test.go b/wallet/messages_test.go index fec55f71..b6bb49e2 100644 --- a/wallet/messages_test.go +++ b/wallet/messages_test.go @@ -2,6 +2,7 @@ package wallet import ( "crypto/ed25519" + "encoding/hex" "fmt" "reflect" "testing" @@ -18,6 +19,14 @@ func mustFromHex(msg string) *boc.Cell { return c } +func mustPubkeyFromHex(hexPubkey string) ed25519.PublicKey { + bytes, err := hex.DecodeString(hexPubkey) + if err != nil { + panic(err) + } + return ed25519.PublicKey(bytes) +} + func TestExtractRawMessages(t *testing.T) { tests := []struct { name string @@ -59,6 +68,25 @@ func TestExtractRawMessages(t *testing.T) { }, }, }, + { + name: "v5", + boc: "te6ccgECCAEAAZ4AAfGIAehvqHPiQ2Ru+zkowjJx/7oJbqEYRnlCOuPe5+2gm24WA5tLO3f////oAAAAAAADMYd8kAAAAAEHzN670eqqNU3yWGkX1dOynyAbT7DN4cFDpE0r+nInTomGrifjPTaZvG3YxYzTHpLoNesGc9s5Q0tHlLNcFNQeAQIKDsPIbQMCAwIKDsPIbQMEBQCpaAHob6hz4kNkbvs5KMIycf+6CW6hGEZ5Qjrj3uftoJtuFwAbM0yWoWMN5aT+uK8qrHCkGgxpOEKbDu0Tui2Fbyh0iAy3GwAAAAAAAAAAAAAAAAAAQAIKDsPIbQMGBwCpaAHob6hz4kNkbvs5KMIycf+6CW6hGEZ5Qjrj3uftoJtuFwAbM0yWoWMN5aT+uK8qrHCkGgxpOEKbDu0Tui2Fbyh0iAx6EgAAAAAAAAAAAAAAAAAAQAAAAKloAehvqHPiQ2Ru+zkowjJx/7oJbqEYRnlCOuPe5+2gm24XABszTJahYw3lpP64ryqscKQaDGk4QpsO7RO6LYVvKHSIDD0JAAAAAAAAAAAAAAAAAABA", + ver: V5R1, + want: []RawMessage{ + { + Message: mustFromHex("te6ccgEBAQEAVwAAqWgB6G+oc+JDZG77OSjCMnH/ugluoRhGeUI6497n7aCbbhcAGzNMlqFjDeWk/rivKqxwpBoMaThCmw7tE7othW8odIgMtxsAAAAAAAAAAAAAAAAAAEA="), + Mode: 3, + }, + { + Message: mustFromHex("te6ccgEBAQEAVwAAqWgB6G+oc+JDZG77OSjCMnH/ugluoRhGeUI6497n7aCbbhcAGzNMlqFjDeWk/rivKqxwpBoMaThCmw7tE7othW8odIgMehIAAAAAAAAAAAAAAAAAAEA="), + Mode: 3, + }, + { + Message: mustFromHex("te6ccgEBAQEAVwAAqWgB6G+oc+JDZG77OSjCMnH/ugluoRhGeUI6497n7aCbbhcAGzNMlqFjDeWk/rivKqxwpBoMaThCmw7tE7othW8odIgMPQkAAAAAAAAAAAAAAAAAAEA="), + Mode: 3, + }, + }, + }, { name: "highload", boc: "te6ccgECCQEAAUMAAUWIAbeTPaOhIeFpX00pVBankGP2F/kaObq5EAdGLvI+omE+DAEBmXzKceTPz+weyz8nYZbOkpsBYbvy6gN7h38ZVL6RTqln7XbUzHkQqxRp1B1ZYkBgMW1NtE7r8Jwg26HcS3qPiwYAAYiUZMJyTpfTrVXAAgIFngACAwQBAwDgBQEDAOAHAWJCADZmmS1CxhvLSf1xXlVY4Ug0GNJwhTYd2id0WwreUOkQCKAAAAAAAAAAAAAAAAABBgBQAAAAADcwMzBhYzQ2LWI5NWMtNDRjNy04ZDdiLTYxMjMyNmU2ZTUxMgFiQgA2ZpktQsYby0n9cV5VWOFINBjScIU2HdondFsK3lDpEAlAAAAAAAAAAAAAAAAAAQgAUAAAAAAzYjA2OTU1YS03YjRjLTQ1YWEtOTVlNy0wNTI4ZWZhYjAyM2E=", @@ -161,3 +189,62 @@ func TestSignedMsgBody_Verify(t *testing.T) { }) } } + +func TestMessageV5VerifySignature(t *testing.T) { + tests := []struct { + name string + boc string + publicKey ed25519.PublicKey + invalidPublicKeys []ed25519.PublicKey + wantErr bool + }{ + { + name: "wallet v5", + boc: "te6ccgECCAEAAZ4AAfGIAehvqHPiQ2Ru+zkowjJx/7oJbqEYRnlCOuPe5+2gm24WA5tLO3f////oAAAAAAADMY8YiAAAADPkc94coPiaMQo1EI1uuJWlVQGxiffff96PyOTGiQhUjkr733UkT8rfdXxuYcb9SMykg8Tlo7LNBB187eI+ymw2AQIKDsPIbQMCAwIKDsPIbQMEBQCpaAHob6hz4kNkbvs5KMIycf+6CW6hGEZ5Qjrj3uftoJtuFwAbM0yWoWMN5aT+uK8qrHCkGgxpOEKbDu0Tui2Fbyh0iAy3GwAAAAAAAAAAAAAAAAAAQAIKDsPIbQMGBwCpaAHob6hz4kNkbvs5KMIycf+6CW6hGEZ5Qjrj3uftoJtuFwAbM0yWoWMN5aT+uK8qrHCkGgxpOEKbDu0Tui2Fbyh0iAx6EgAAAAAAAAAAAAAAAAAAQAAAAKloAehvqHPiQ2Ru+zkowjJx/7oJbqEYRnlCOuPe5+2gm24XABszTJahYw3lpP64ryqscKQaDGk4QpsO7RO6LYVvKHSIDD0JAAAAAAAAAAAAAAAAAABA", + publicKey: mustPubkeyFromHex("406b63856ff6913fe2170a5c128113c6bd8256438a43340ea3bf6e0bbc56f9ca"), + invalidPublicKeys: []ed25519.PublicKey{ + mustPubkeyFromHex("406b63856ff6913fe2170a5c128113c6bd8256438a43340ea3bf6e0bbc56f9bb"), + mustPubkeyFromHex("406b63856ff6913fe2170a5c128113c6bd8256438a43340ea3bf6e0bbc560000"), + mustPubkeyFromHex("cfa50eeb1c3293c92bd33d5aa672c1717accd8a21b96033debb6d30b5bb230df"), + }, + }, + { + name: "wallet v5", + boc: "te6ccgECCAEAAZ4AAfGIAVjXuMKpIWGwKJenbsOOEh1AEZo6J5Zu0R8EDI37LVyKA5tLO3f////oAAAAAAADMY9YuAAAAAFs/6Zj178nNgWPsbSM2UaEwrcyYPF0kSqZ4d+fhPMfynWRWKBCiVh2PtDewtHZ5FW1luvfXHDqGX0DtYSHfVwGAQIKDsPIbQMCAwIKDsPIbQMEBQCpaAFY17jCqSFhsCiXp27DjhIdQBGaOieWbtEfBAyN+y1ciwAbM0yWoWMN5aT+uK8qrHCkGgxpOEKbDu0Tui2Fbyh0iAy3GwAAAAAAAAAAAAAAAAAAQAIKDsPIbQMGBwCpaAFY17jCqSFhsCiXp27DjhIdQBGaOieWbtEfBAyN+y1ciwAbM0yWoWMN5aT+uK8qrHCkGgxpOEKbDu0Tui2Fbyh0iAx6EgAAAAAAAAAAAAAAAAAAQAAAAKloAVjXuMKpIWGwKJenbsOOEh1AEZo6J5Zu0R8EDI37LVyLABszTJahYw3lpP64ryqscKQaDGk4QpsO7RO6LYVvKHSIDD0JAAAAAAAAAAAAAAAAAABA", + publicKey: mustPubkeyFromHex("cfa50eeb1c3293c92bd33d5aa672c1717accd8a21b96033debb6d30b5bb230df"), + invalidPublicKeys: []ed25519.PublicKey{ + mustPubkeyFromHex("406b63856ff6913fe2170a5c128113c6bd8256438a43340ea3bf6e0bbc56f9bb"), + mustPubkeyFromHex("406b63856ff6913fe2170a5c128113c6bd8256438a43340ea3bf6e0bbc56f9ca"), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cell := mustFromHex(tt.boc) + var m tlb.Message + if err := tlb.Unmarshal(cell, &m); err != nil { + t.Fatalf("Unmarshal() failed: %v", err) + } + msgBody := boc.Cell(m.Body.Value) + err := MessageV5VerifySignature(msgBody, tt.publicKey) + if tt.wantErr { + if err == nil { + t.Fatalf("MessageV5VerifySignature() had to fail but it didn't") + } + if err.Error() != ErrBadSignature.Error() { + t.Fatalf("MessageV5VerifySignature() failed: %v", err) + } + return + } + if err != nil { + t.Fatalf("MessageV5VerifySignature() failed: %v", err) + } + + for _, publicKey := range tt.invalidPublicKeys { + if err = MessageV5VerifySignature(msgBody, publicKey); err == nil { + t.Fatalf("MessageV5VerifySignature() had to fail but it didn't") + } + } + }) + } +} diff --git a/wallet/models.go b/wallet/models.go index 84af7b36..b6589e88 100644 --- a/wallet/models.go +++ b/wallet/models.go @@ -23,6 +23,7 @@ const ( V3R2 V4R1 V4R2 + V5R1 HighLoadV1R1 HighLoadV1R2 HighLoadV2 @@ -54,6 +55,7 @@ var codes = map[Version]string{ V3R2: "te6cckEBAQEAcQAA3v8AIN0gggFMl7ohggEznLqxn3Gw7UTQ0x/THzHXC//jBOCk8mCDCNcYINMf0x/TH/gjE7vyY+1E0NMf0x/T/9FRMrryoVFEuvKiBPkBVBBV+RDyo/gAkyDXSpbTB9QC+wDo0QGkyMsfyx/L/8ntVBC9ba0=", V4R1: "te6cckECFQEAAvUAART/APSkE/S88sgLAQIBIAIDAgFIBAUE+PKDCNcYINMf0x/THwL4I7vyY+1E0NMf0x/T//QE0VFDuvKhUVG68qIF+QFUEGT5EPKj+AAkpMjLH1JAyx9SMMv/UhD0AMntVPgPAdMHIcAAn2xRkyDXSpbTB9QC+wDoMOAhwAHjACHAAuMAAcADkTDjDQOkyMsfEssfy/8REhMUA+7QAdDTAwFxsJFb4CHXScEgkVvgAdMfIYIQcGx1Z70ighBibG5jvbAighBkc3RyvbCSXwPgAvpAMCD6RAHIygfL/8nQ7UTQgQFA1yH0BDBcgQEI9ApvoTGzkl8F4ATTP8glghBwbHVnupEx4w0kghBibG5juuMABAYHCAIBIAkKAFAB+gD0BDCCEHBsdWeDHrFwgBhQBcsFJ88WUAP6AvQAEstpyx9SEMs/AFL4J28ighBibG5jgx6xcIAYUAXLBSfPFiT6AhTLahPLH1Iwyz8B+gL0AACSghBkc3Ryuo41BIEBCPRZMO1E0IEBQNcgyAHPFvQAye1UghBkc3Rygx6xcIAYUATLBVjPFiL6AhLLassfyz+UEDRfBOLJgED7AAIBIAsMAFm9JCtvaiaECAoGuQ+gIYRw1AgIR6STfSmRDOaQPp/5g3gSgBt4EBSJhxWfMYQCAVgNDgARuMl+1E0NcLH4AD2ynftRNCBAUDXIfQEMALIygfL/8nQAYEBCPQKb6ExgAgEgDxAAGa3OdqJoQCBrkOuF/8AAGa8d9qJoQBBrkOuFj8AAbtIH+gDU1CL5AAXIygcVy//J0Hd0gBjIywXLAiLPFlAF+gIUy2sSzMzJcfsAyEAUgQEI9FHypwIAbIEBCNcYyFQgJYEBCPRR8qeCEG5vdGVwdIAYyMsFywJQBM8WghAF9eEA+gITy2oSyx/JcfsAAgBygQEI1xgwUgKBAQj0WfKn+CWCEGRzdHJwdIAYyMsFywJQBc8WghAF9eEA+gIUy2oTyx8Syz/Jc/sAAAr0AMntVEap808=", V4R2: "te6cckECFAEAAtQAART/APSkE/S88sgLAQIBIAIDAgFIBAUE+PKDCNcYINMf0x/THwL4I7vyZO1E0NMf0x/T//QE0VFDuvKhUVG68qIF+QFUEGT5EPKj+AAkpMjLH1JAyx9SMMv/UhD0AMntVPgPAdMHIcAAn2xRkyDXSpbTB9QC+wDoMOAhwAHjACHAAuMAAcADkTDjDQOkyMsfEssfy/8QERITAubQAdDTAyFxsJJfBOAi10nBIJJfBOAC0x8hghBwbHVnvSKCEGRzdHK9sJJfBeAD+kAwIPpEAcjKB8v/ydDtRNCBAUDXIfQEMFyBAQj0Cm+hMbOSXwfgBdM/yCWCEHBsdWe6kjgw4w0DghBkc3RyupJfBuMNBgcCASAICQB4AfoA9AQw+CdvIjBQCqEhvvLgUIIQcGx1Z4MesXCAGFAEywUmzxZY+gIZ9ADLaRfLH1Jgyz8gyYBA+wAGAIpQBIEBCPRZMO1E0IEBQNcgyAHPFvQAye1UAXKwjiOCEGRzdHKDHrFwgBhQBcsFUAPPFiP6AhPLassfyz/JgED7AJJfA+ICASAKCwBZvSQrb2omhAgKBrkPoCGEcNQICEekk30pkQzmkD6f+YN4EoAbeBAUiYcVnzGEAgFYDA0AEbjJftRNDXCx+AA9sp37UTQgQFA1yH0BDACyMoHy//J0AGBAQj0Cm+hMYAIBIA4PABmtznaiaEAga5Drhf/AABmvHfaiaEAQa5DrhY/AAG7SB/oA1NQi+QAFyMoHFcv/ydB3dIAYyMsFywIizxZQBfoCFMtrEszMyXP7AMhAFIEBCPRR8qcCAHCBAQjXGPoA0z/IVCBHgQEI9FHyp4IQbm90ZXB0gBjIywXLAlAGzxZQBPoCFMtqEssfyz/Jc/sAAgBsgQEI1xj6ANM/MFIkgQEI9Fnyp4IQZHN0cnB0gBjIywXLAlAFzxZQA/oCE8tqyx8Syz/Jc/sAAAr0AMntVGliJeU=", + V5R1: "te6ccgEBAQEAIwAIQgLkzzsvTG1qYeoPK1RH0mZ4WyavNjfbLe7mvNGqgm80Eg==", HighLoadV1R1: "te6ccgEBBgEAhgABFP8A9KQT9KDyyAsBAgEgAgMCAUgEBQC88oMI1xgg0x/TH9Mf+CMTu/Jj7UTQ0x/TH9P/0VEyuvKhUUS68qIE+QFUEFX5EPKj9ATR+AB/jhghgBD0eG+hb6EgmALTB9QwAfsAkTLiAbPmWwGkyMsfyx/L/8ntVAAE0DAAEaCZL9qJoa4WPw==", HighLoadV1R2: "te6ccgEBCAEAmQABFP8A9KQT9LzyyAsBAgEgAgMCAUgEBQC88oMI1xgg0x/TH9Mf+CMTu/Jj7UTQ0x/TH9P/0VEyuvKhUUS68qIE+QFUEFX5EPKj9ATR+AB/jhghgBD0eG+hb6EgmALTB9QwAfsAkTLiAbPmWwGkyMsfyx/L/8ntVAAE0DACAUgGBwAXuznO1E0NM/MdcL/4ABG4yX7UTQ1wsfg=", HighLoadV2: "te6ccgEBCQEA5QABFP8A9KQT9LzyyAsBAgEgAgcCAUgDBAAE0DACASAFBgAXvZznaiaGmvmOuF/8AEG+X5dqJoaY+Y6Z/p/5j6AmipEEAgegc30JjJLb/JXdHxQB6vKDCNcYINMf0z/4I6ofUyC58mPtRNDTH9M/0//0BNFTYIBA9A5voTHyYFFzuvKiB/kBVBCH+RDyowL0BNH4AH+OFiGAEPR4b6UgmALTB9QwAfsAkTLiAbPmW4MlochANIBA9EOK5jEByMsfE8s/y//0AMntVAgANCCAQPSWb6VsEiCUMFMDud4gkzM2AZJsIeKz", @@ -142,7 +144,7 @@ func GetVerByCodeHash(hash tlb.Bits256) (Version, bool) { } func (v Version) ToString() string { - names := []string{"v1R1", "v1R2", "v1R3", "v2R1", "v2R2", "v3R1", "v3R2", "v4R1", "v4R2", "highload_v1R1", "highload_v1R2", "highload_v2", "highload_v2R1", "highload_v2R2"} + names := []string{"v1R1", "v1R2", "v1R3", "v2R1", "v2R2", "v3R1", "v3R2", "v4R1", "v4R2", "v5R1", "highload_v1R1", "highload_v1R2", "highload_v2", "highload_v2R1", "highload_v2R2"} if int(v) > len(names) { panic("to string conversion for this ver not supported") }