From 4ae95c72fa5a76d9d562304a0118f2686672451e Mon Sep 17 00:00:00 2001 From: Nikolay Eskov Date: Thu, 7 Dec 2023 18:03:24 +0300 Subject: [PATCH] Tx snapshot protobuf fixes (#1261) * Use full address instead of address body for protobuf messages. * Use 'NewAddressFromBytesChecked' for address unmarshalling. * Fix alias snapshot unmarshalling from protobuf. * Add more checks on protobuf data for snapshots. * Add 'TestTxSnapshotMarshalToPBAndUnmarshalFromPB'. * Fix 'TODO' for 'ProtobufConverter.entry'. --- pkg/proto/protobuf_converters.go | 6 +- pkg/proto/snapshot_types.go | 69 +++++++++++++------ pkg/proto/snapshot_types_test.go | 109 +++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 23 deletions(-) create mode 100644 pkg/proto/snapshot_types_test.go diff --git a/pkg/proto/protobuf_converters.go b/pkg/proto/protobuf_converters.go index afdf917d2..4836f59e6 100644 --- a/pkg/proto/protobuf_converters.go +++ b/pkg/proto/protobuf_converters.go @@ -734,7 +734,7 @@ func (c *ProtobufConverter) entry(entry *g.DataEntry) DataEntry { return nil } var e DataEntry - switch t := entry.Value.(type) { // TODO: change delete data entry to "case nil" and return an error in default + switch t := entry.Value.(type) { case *g.DataEntry_IntValue: e = &IntegerDataEntry{Key: entry.Key, Value: t.IntValue} case *g.DataEntry_BoolValue: @@ -743,8 +743,10 @@ func (c *ProtobufConverter) entry(entry *g.DataEntry) DataEntry { e = &BinaryDataEntry{Key: entry.Key, Value: t.BinaryValue} case *g.DataEntry_StringValue: e = &StringDataEntry{Key: entry.Key, Value: t.StringValue} - default: // No value means DeleteDataEntry + case nil: e = &DeleteDataEntry{Key: entry.Key} + default: + c.err = errors.Errorf("unknown data entry value type (%T)", entry.Value) } return e } diff --git a/pkg/proto/snapshot_types.go b/pkg/proto/snapshot_types.go index 18cc18e44..d814b94a9 100644 --- a/pkg/proto/snapshot_types.go +++ b/pkg/proto/snapshot_types.go @@ -29,7 +29,7 @@ func (s WavesBalanceSnapshot) Apply(a SnapshotApplier) error { return a.ApplyWav func (s WavesBalanceSnapshot) ToProtobuf() (*g.TransactionStateSnapshot_Balance, error) { return &g.TransactionStateSnapshot_Balance{ - Address: s.Address.Body(), + Address: s.Address.Bytes(), Amount: &g.Amount{ AssetId: nil, Amount: int64(s.Balance), @@ -48,7 +48,7 @@ func (s WavesBalanceSnapshot) AppendToProtobuf(txSnapshots *g.TransactionStateSn func (s *WavesBalanceSnapshot) FromProtobuf(scheme Scheme, p *g.TransactionStateSnapshot_Balance) error { var c ProtobufConverter - addr, err := c.Address(scheme, p.Address) + addr, err := NewAddressFromBytesChecked(scheme, p.Address) if err != nil { return err } @@ -78,7 +78,7 @@ func (s AssetBalanceSnapshot) Apply(a SnapshotApplier) error { return a.ApplyAss func (s AssetBalanceSnapshot) ToProtobuf() (*g.TransactionStateSnapshot_Balance, error) { return &g.TransactionStateSnapshot_Balance{ - Address: s.Address.Body(), + Address: s.Address.Bytes(), Amount: &g.Amount{ AssetId: s.AssetID.Bytes(), Amount: int64(s.Balance), @@ -88,7 +88,7 @@ func (s AssetBalanceSnapshot) ToProtobuf() (*g.TransactionStateSnapshot_Balance, func (s *AssetBalanceSnapshot) FromProtobuf(scheme Scheme, p *g.TransactionStateSnapshot_Balance) error { var c ProtobufConverter - addr, err := c.Address(scheme, p.Address) + addr, err := NewAddressFromBytesChecked(scheme, p.Address) if err != nil { return err } @@ -131,7 +131,7 @@ func (s DataEntriesSnapshot) ToProtobuf() (*g.TransactionStateSnapshot_AccountDa entries = append(entries, e.ToProtobuf()) } return &g.TransactionStateSnapshot_AccountData{ - Address: s.Address.Body(), + Address: s.Address.Bytes(), Entries: entries, }, nil } @@ -147,7 +147,7 @@ func (s DataEntriesSnapshot) AppendToProtobuf(txSnapshots *g.TransactionStateSna func (s *DataEntriesSnapshot) FromProtobuf(scheme Scheme, p *g.TransactionStateSnapshot_AccountData) error { var c ProtobufConverter - addr, err := c.Address(scheme, p.Address) + addr, err := NewAddressFromBytesChecked(scheme, p.Address) if err != nil { return err } @@ -205,9 +205,13 @@ func (s *AccountScriptSnapshot) FromProtobuf(p *g.TransactionStateSnapshot_Accou if c.err != nil { return c.err } + verifierComplexity := c.uint64(p.VerifierComplexity) + if c.err != nil { + return c.err + } s.SenderPublicKey = publicKey s.Script = script - s.VerifierComplexity = uint64(p.VerifierComplexity) + s.VerifierComplexity = verifierComplexity return nil } @@ -270,7 +274,7 @@ func (s LeaseBalanceSnapshot) Apply(a SnapshotApplier) error { return a.ApplyLea func (s LeaseBalanceSnapshot) ToProtobuf() (*g.TransactionStateSnapshot_LeaseBalance, error) { return &g.TransactionStateSnapshot_LeaseBalance{ - Address: s.Address.Body(), + Address: s.Address.Bytes(), In: int64(s.LeaseIn), Out: int64(s.LeaseOut), }, nil @@ -286,14 +290,22 @@ func (s LeaseBalanceSnapshot) AppendToProtobuf(txSnapshots *g.TransactionStateSn } func (s *LeaseBalanceSnapshot) FromProtobuf(scheme Scheme, p *g.TransactionStateSnapshot_LeaseBalance) error { - var c ProtobufConverter - addr, err := c.Address(scheme, p.Address) + addr, err := NewAddressFromBytesChecked(scheme, p.Address) if err != nil { return err } + var c ProtobufConverter + in := c.uint64(p.In) + if c.err != nil { + return c.err + } + out := c.uint64(p.Out) + if c.err != nil { + return c.err + } s.Address = addr - s.LeaseIn = uint64(p.In) - s.LeaseOut = uint64(p.Out) + s.LeaseIn = in + s.LeaseOut = out return nil } @@ -356,7 +368,7 @@ func (s *NewLeaseSnapshot) FromProtobuf(scheme Scheme, p *g.TransactionStateSnap if c.err != nil { return c.err } - recipientAddr, err := c.Address(scheme, p.RecipientAddress) + recipientAddr, err := NewAddressFromBytesChecked(scheme, p.RecipientAddress) if err != nil { return err } @@ -435,8 +447,12 @@ func (s *SponsorshipSnapshot) FromProtobuf(p *g.TransactionStateSnapshot_Sponsor if c.err != nil { return c.err } + minFee := c.uint64(p.MinFee) + if c.err != nil { + return c.err + } s.AssetID = assetID - s.MinSponsoredFee = uint64(p.MinFee) + s.MinSponsoredFee = minFee return nil } @@ -453,7 +469,7 @@ func (s AliasSnapshot) Apply(a SnapshotApplier) error { return a.ApplyAlias(s) } func (s AliasSnapshot) ToProtobuf() (*g.TransactionStateSnapshot_Alias, error) { return &g.TransactionStateSnapshot_Alias{ - Address: s.Address.Body(), + Address: s.Address.Bytes(), Alias: s.Alias.Alias, }, nil } @@ -471,13 +487,12 @@ func (s AliasSnapshot) AppendToProtobuf(txSnapshots *g.TransactionStateSnapshot) } func (s *AliasSnapshot) FromProtobuf(scheme Scheme, p *g.TransactionStateSnapshot_Alias) error { - var c ProtobufConverter - addr, err := c.Address(scheme, p.Address) + addr, err := NewAddressFromBytesChecked(scheme, p.Address) if err != nil { return err } s.Address = addr - s.Alias.Alias = p.Alias + s.Alias = *NewAlias(scheme, p.Alias) return nil } @@ -517,9 +532,17 @@ func (s *FilledVolumeFeeSnapshot) FromProtobuf(p *g.TransactionStateSnapshot_Ord if c.err != nil { return c.err } + volume := c.uint64(p.Volume) + if c.err != nil { + return c.err + } + fee := c.uint64(p.Fee) + if c.err != nil { + return c.err + } s.OrderID = orderID - s.FilledVolume = uint64(p.Volume) - s.FilledFee = uint64(p.Fee) + s.FilledVolume = volume + s.FilledFee = fee return nil } @@ -564,9 +587,13 @@ func (s *NewAssetSnapshot) FromProtobuf(p *g.TransactionStateSnapshot_NewAsset) if c.err != nil { return c.err } + decimals := c.byte(p.Decimals) + if c.err != nil { + return c.err + } s.AssetID = assetID s.IssuerPublicKey = publicKey - s.Decimals = uint8(p.Decimals) + s.Decimals = decimals s.IsNFT = p.Nft return nil } diff --git a/pkg/proto/snapshot_types_test.go b/pkg/proto/snapshot_types_test.go new file mode 100644 index 000000000..cc240a6cf --- /dev/null +++ b/pkg/proto/snapshot_types_test.go @@ -0,0 +1,109 @@ +package proto_test + +import ( + "encoding/base64" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + g "github.com/wavesplatform/gowaves/pkg/grpc/generated/waves" + "github.com/wavesplatform/gowaves/pkg/proto" +) + +func TestTxSnapshotMarshalToPBAndUnmarshalFromPB(t *testing.T) { + const scheme = proto.TestNetScheme + testCases := []struct { + testCaseName string + pbInBase64 string + }{ + { + testCaseName: "waves_balances", + pbInBase64: "CiQKGgFUYP1Q7yDeRXEgffuciL58HC+KIscK2I+1EgYQgJTr3AMKJAoaAVRCxcljc/UP2BNQYE8cFPKmySVq2v0ZsCoSBhCAqNa5Bw==", //nolint:lll + }, + { + testCaseName: "asset_balances", + pbInBase64: "CkMKGgFUYP1Q7yDeRXEgffuciL58HC+KIscK2I+1EiUKIF5mn4IKZ9CIbYdHjPBDoqx4XMevVdwxzhB1OUvTUKJbEJBOCkQKGgFUQsXJY3P1D9gTUGBPHBTypsklatr9GbAqEiYKIHidwBEj1TYPcIKv1LRquL/otRYLv7UmwEPl/Hg6T4lOEKCcAQ==", //nolint:lll + }, + { + testCaseName: "data_entries", + pbInBase64: "YloKGgFUYP1Q7yDeRXEgffuciL58HC+KIscK2I+1EgUKA2ZvbxISCgNiYXJqC1N0cmluZ1ZhbHVlEiEKA2JhemIaAVRg/VDvIN5FcSB9+5yIvnwcL4oixwrYj7ViLwoaAVRCxcljc/UP2BNQYE8cFPKmySVq2v0ZsCoSCAoDZm9vULAJEgcKA2JhclgB", //nolint:lll + }, + { + testCaseName: "account_script", + pbInBase64: "Wi4KIFDHWa9Cd6VU8M20LLFHzbBTveERf1sEOw19SUS40GBoEgcGAQaw0U/PGPoB", + }, + { + testCaseName: "asset_script", + pbInBase64: "QisKIHidwBEj1TYPcIKv1LRquL/otRYLv7UmwEPl/Hg6T4lOEgcGAQaw0U/P", + }, + { + testCaseName: "new_lease", + pbInBase64: "EiIKGgFUYP1Q7yDeRXEgffuciL58HC+KIscK2I+1GICa4uEQEiIKGgFUQsXJY3P1D9gTUGBPHBTypsklatr9GbAqEICuzb4UGmYKILiCMyyFggW8Zd2LGt/AtMr7WWp+kfWbzlN93pXZqzqNEiBQx1mvQnelVPDNtCyxR82wU73hEX9bBDsNfUlEuNBgaBoaAVRCxcljc/UP2BNQYE8cFPKmySVq2v0ZsCoggPKLqAk=", //nolint:lll + }, + { + testCaseName: "cancelled_lease", + pbInBase64: "EiIKGgFUMCPLqLW81X2Atgaj2KwF9QkaJq47Cev9GICo1rkHEhwKGgFUYSJd8vzI9rq7GdIuDy65JMc8zi497E98IiIKILiCMyyFggW8Zd2LGt/AtMr7WWp+kfWbzlN93pXZqzqN", //nolint:lll + }, + { + testCaseName: "sponsorship", + pbInBase64: "aiUKIHidwBEj1TYPcIKv1LRquL/otRYLv7UmwEPl/Hg6T4lOEPwq", + }, + { + testCaseName: "alias", + pbInBase64: "SiYKGgFUQsXJY3P1D9gTUGBPHBTypsklatr9GbAqEgh3YXZlc2V2bw==", + }, + { + testCaseName: "order_fill", + pbInBase64: "UisKIMkknO8yHpMUT/XKkkdlrbYCG0Dt+qvVgphfgtRbyRDMEICU69wDGNAPUisKIJZ9YwvJObbWItHAD2zhbaFOTFx2zQ4p0Xbo81GXHKeEEICU69wDGNAP", //nolint:lll + }, + { + testCaseName: "new_asset", + pbInBase64: "KkYKIF5mn4IKZ9CIbYdHjPBDoqx4XMevVdwxzhB1OUvTUKJbEiDcYGFqY9MotHTpDpskoycN/Mt62bZfPxIC4fpU0ZTBniABKkYKIHidwBEj1TYPcIKv1LRquL/otRYLv7UmwEPl/Hg6T4lOEiDcYGFqY9MotHTpDpskoycN/Mt62bZfPxIC4fpU0ZTBnhgIMi8KIHidwBEj1TYPcIKv1LRquL/otRYLv7UmwEPl/Hg6T4lOEAEaCQT/////////9jIlCiBeZp+CCmfQiG2HR4zwQ6KseFzHr1XcMc4QdTlL01CiWxoBAQ==", //nolint:lll + }, + { + testCaseName: "reissued_asset", + pbInBase64: "MigKIDhvjT3TTlJ+v4Ni205vcYc1m9WWgnQPFovjmJI1H62yGgQ7msoA", + }, + { + testCaseName: "renamed_asset", + pbInBase64: "OkMKIHidwBEj1TYPcIKv1LRquL/otRYLv7UmwEPl/Hg6T4lOEgduZXduYW1lGhZzb21lIGZhbmN5IGRlc2NyaXB0aW9u", + }, + { + testCaseName: "failed_transaction", + pbInBase64: "CiQKGgFUQsXJY3P1D9gTUGBPHBTypsklatr9GbAqEgYQ4PHE1wlwAQ==", + }, + { + testCaseName: "elided_transaction", + pbInBase64: "cAI=", + }, + { + testCaseName: "all_together", + pbInBase64: "CkMKGgFUYP1Q7yDeRXEgffuciL58HC+KIscK2I+1EiUKIF5mn4IKZ9CIbYdHjPBDoqx4XMevVdwxzhB1OUvTUKJbEJBOCkQKGgFUQsXJY3P1D9gTUGBPHBTypsklatr9GbAqEiYKIHidwBEj1TYPcIKv1LRquL/otRYLv7UmwEPl/Hg6T4lOEKCcAQokChoBVGD9UO8g3kVxIH37nIi+fBwviiLHCtiPtRIGEICU69wDCiQKGgFUQsXJY3P1D9gTUGBPHBTypsklatr9GbAqEgYQgKjWuQcSIgoaAVRg/VDvIN5FcSB9+5yIvnwcL4oixwrYj7UYgJri4RASIgoaAVRCxcljc/UP2BNQYE8cFPKmySVq2v0ZsCoQgK7NvhQSIgoaAVQwI8uotbzVfYC2BqPYrAX1CRomrjsJ6/0YgKjWuQcSHAoaAVRhIl3y/Mj2ursZ0i4PLrkkxzzOLj3sT3waZgoguIIzLIWCBbxl3Ysa38C0yvtZan6R9ZvOU33eldmrOo0SIFDHWa9Cd6VU8M20LLFHzbBTveERf1sEOw19SUS40GBoGhoBVELFyWNz9Q/YE1BgTxwU8qbJJWra/RmwKiCA8ouoCSIiCiC4gjMshYIFvGXdixrfwLTK+1lqfpH1m85Tfd6V2as6jSpGCiBeZp+CCmfQiG2HR4zwQ6KseFzHr1XcMc4QdTlL01CiWxIg3GBhamPTKLR06Q6bJKMnDfzLetm2Xz8SAuH6VNGUwZ4gASpGCiB4ncARI9U2D3CCr9S0ari/6LUWC7+1JsBD5fx4Ok+JThIg3GBhamPTKLR06Q6bJKMnDfzLetm2Xz8SAuH6VNGUwZ4YCDIvCiB4ncARI9U2D3CCr9S0ari/6LUWC7+1JsBD5fx4Ok+JThABGgkE//////////YyJQogXmafggpn0Ihth0eM8EOirHhcx69V3DHOEHU5S9NQolsaAQEyKAogOG+NPdNOUn6/g2LbTm9xhzWb1ZaCdA8Wi+OYkjUfrbIaBDuaygA6QwogeJ3AESPVNg9wgq/UtGq4v+i1Fgu/tSbAQ+X8eDpPiU4SB25ld25hbWUaFnNvbWUgZmFuY3kgZGVzY3JpcHRpb25KJgoaAVRCxcljc/UP2BNQYE8cFPKmySVq2v0ZsCoSCHdhdmVzZXZvUisKIMkknO8yHpMUT/XKkkdlrbYCG0Dt+qvVgphfgtRbyRDMEICU69wDGNAPUisKIJZ9YwvJObbWItHAD2zhbaFOTFx2zQ4p0Xbo81GXHKeEEICU69wDGNAPWi4KIFDHWa9Cd6VU8M20LLFHzbBTveERf1sEOw19SUS40GBoEgcGAQaw0U/PGPoBYloKGgFUYP1Q7yDeRXEgffuciL58HC+KIscK2I+1EgUKA2ZvbxISCgNiYXJqC1N0cmluZ1ZhbHVlEiEKA2JhemIaAVRg/VDvIN5FcSB9+5yIvnwcL4oixwrYj7ViLwoaAVRCxcljc/UP2BNQYE8cFPKmySVq2v0ZsCoSCAoDZm9vULAJEgcKA2JhclgBaiUKIHidwBEj1TYPcIKv1LRquL/otRYLv7UmwEPl/Hg6T4lOEPwqcAE=", //nolint:lll + }, + } + for _, testCase := range testCases { + t.Run(testCase.testCaseName, func(t *testing.T) { + expectedData, err := base64.StdEncoding.DecodeString(testCase.pbInBase64) + require.NoError(t, err) + + expectedTxSnapshotProto := new(g.TransactionStateSnapshot) + err = expectedTxSnapshotProto.UnmarshalVT(expectedData) + require.NoError(t, err) + + txSnapshot, err := proto.TxSnapshotsFromProtobuf(scheme, expectedTxSnapshotProto) + assert.NoError(t, err) + + txSnapshotProto := new(g.TransactionStateSnapshot) + for _, snapshot := range txSnapshot { + appendErr := snapshot.AppendToProtobuf(txSnapshotProto) + require.NoError(t, appendErr) + } + assert.Equal(t, expectedTxSnapshotProto, txSnapshotProto) + + marshaledData, err := txSnapshotProto.MarshalVTStrict() + require.NoError(t, err) + assert.Equal(t, expectedData, marshaledData) + }) + } +}