From 93801f631a5d8a1c5d315a0329659e098c10a6d4 Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Fri, 3 Jun 2022 17:41:24 +0200 Subject: [PATCH 1/6] Split keys methods according to sdk version --- tracelistener/keys.go | 144 -------------- tracelistener/processor/bank.go | 3 +- tracelistener/processor/bank_test.go | 29 ++- tracelistener/processor/cw20_balance.go | 27 +-- tracelistener/processor/cw20_token_info.go | 30 +-- .../processor/datamarshaler/datamarshaler.go | 2 + .../processor/datamarshaler/impl_v42.go | 7 + .../processor/datamarshaler/impl_v44.go | 43 +++- tracelistener/processor/datamarshaler/keys.go | 30 +++ .../processor/datamarshaler/keys_test.go | 66 +++++++ .../processor/datamarshaler/keys_v42.go | 18 +- .../processor/datamarshaler/keys_v44.go | 183 +++++++++++++++++- .../datamarshaler/keys_v44_test.go} | 141 ++++++++------ 13 files changed, 446 insertions(+), 277 deletions(-) delete mode 100644 tracelistener/keys.go create mode 100644 tracelistener/processor/datamarshaler/keys.go create mode 100644 tracelistener/processor/datamarshaler/keys_test.go rename tracelistener/{keys_test.go => processor/datamarshaler/keys_v44_test.go} (80%) diff --git a/tracelistener/keys.go b/tracelistener/keys.go deleted file mode 100644 index c84b4508..00000000 --- a/tracelistener/keys.go +++ /dev/null @@ -1,144 +0,0 @@ -package tracelistener - -import ( - "bytes" - "encoding/hex" - "fmt" - - "github.com/cosmos/cosmos-sdk/types/bech32" -) - -// SplitDelegationKey given a key, split it into prefix, delegator and -// validator address. -// param is a list of byte. The key is a concatenation of 5 parts, -// 1. Prefix length: 1 Byte -// 2. Delegator Address Len length: 1 Byte -// 3. Delegator Address length: From 2 -// 4. Validator Address Len length: 1 Byte -// 5. Validator Address length: From 4 -// key : -// Len 1 1 0-255 1 0-255 -// -// Note: Address len 0 does not make sense, but since in the SDK it's "possible" to -// have 0 len address for delegator/validator, we also consider empty address valid. -func SplitDelegationKey(key []byte) (string, string, error) { - // At-least: 3 bytes -> 1, 2, 4 must be present. 1 byte each. - // At-max : 513 bytes -> 3 bytes from (1, 2, 4) + 510 bytes from (3, 5). - if len(key) < 3 || len(key) > (1+1+255+1+255) { - return "", "", fmt.Errorf("malformed key: length %d not in range", len(key)) - } - _, addresses := key[0], key[1:] // Strip the prefix byte. - delAddrLen := addresses[0] // Gets delegator address length - - // We have to keep this check here because this function must split the two addresses, - // FromLengthPrefix only does parsing of a well-formed length-prefix byte slice. - if len(addresses) < int(delAddrLen) { - return "", "", fmt.Errorf("delegator address should be %d bytes long, but it only has %d", delAddrLen, len(addresses)) - } - - totalPrefixedFirstAddressSz := delAddrLen + 1 // we are subslicing including the length-prefix, since FromLengthPrefix uses it - delAddrBytes, err := FromLengthPrefix(addresses[:totalPrefixedFirstAddressSz]) - if err != nil { - return "", "", fmt.Errorf("cannot parse delegator address, %w", err) - } - - delAddr := hex.EncodeToString(delAddrBytes) - - addresses = addresses[totalPrefixedFirstAddressSz:] // Subslice past the delegator address - - valAddrBytes, err := FromLengthPrefix(addresses) // We don't do any subslicing here because FromLengthPrefix will take care of parsing errors - if err != nil { - return "", "", fmt.Errorf("cannot parse validator address, %w", err) - } - - valAddr := hex.EncodeToString(valAddrBytes) - return delAddr, valAddr, nil -} - -// FromLengthPrefix returns the amount of data signaled by the single-byte length prefix in rawData. -func FromLengthPrefix(rawData []byte) ([]byte, error) { - if len(rawData) == 0 { - return nil, fmt.Errorf("data is nil") - } - - length := int(rawData[0]) - rawData = rawData[1:] - if len(rawData) != length { - return nil, fmt.Errorf("length prefix signals %d bytes, but total data is %d bytes long", length, len(rawData)) - } - - return rawData, nil -} - -var ( - wasmContractStorePrefix = []byte{0x03} - wasmContractBalanceKey = append([]byte{0, 7}, []byte("balance")...) - wasmContractTokenInfoKey = []byte("token_info") -) - -// SplitCW20BalanceKey returns the contract and the holder address of a given -// CW20 balance key, or an error if it's not valid. -// param is a list of bytes. The key is a concatenation of 5 parts, -// 1. Prefix length: 1 Byte (always 03 for ContractStorePrefix) -// 2. Contract Address length: 32 Bytes -// 3. Type Len length: 2 Bytes -// 4. Type length: From 3 -// 5. Holder Address length: the remaining bytes -// key : -// Len 1 32 2 0-510 at least 43 -// -// Note: Address len 0 does not make sense, but since in the SDK it's "possible" to -// have 0 len address for delegator/validator, we also consider empty address valid. -func SplitCW20BalanceKey(key []byte) (string, string, error) { - const ( - // At-least: 1+32+2+43 bytes - minLen = 1 + 32 + 2 + 43 - // At-maxLen : 1+32+2+510+43 bytes - maxLen = minLen + 510 - ) - if len(key) < minLen || len(key) > maxLen { - return "", "", - fmt.Errorf("malformed cw20 balance key: length %d not in range %d-%d", - len(key), minLen, maxLen) - } - if !bytes.HasPrefix(key, wasmContractStorePrefix) { - return "", "", fmt.Errorf("not a wasm contract store key") - } - if !bytes.HasPrefix(key[33:], wasmContractBalanceKey) { - return "", "", fmt.Errorf("not a cw20 balance key") - } - contractAddr := hex.EncodeToString(key[1:33]) - // holder addr must be bech32 decoded - _, bz, err := bech32.DecodeAndConvert(string(key[42:])) - if err != nil { - return "", "", fmt.Errorf("decode holder address: %w", err) - } - holderAddr := hex.EncodeToString(bz) - return contractAddr, holderAddr, nil -} - -// SplitCW20TokenInfoKey returns the contract address of a given -// CW20 token_info key, or an error if it's not valid. -// param is a list of bytes. The key is a concatenation of 5 parts, -// 1. Prefix length: 1 Byte (always 03 for ContractStorePrefix) -// 2. Contract Address length: 32 Bytes -// 4. Type length: 10 Bytes (always token_info) -// key : -// Len 1 32 10 -func SplitCW20TokenInfoKey(key []byte) (string, error) { - const expectedLen = 1 + 32 + 10 - if len(key) != expectedLen { - return "", fmt.Errorf( - "malformed cw20 token_info key: length %d not equal to %d", - len(key), expectedLen, - ) - } - if !bytes.HasPrefix(key, wasmContractStorePrefix) { - return "", fmt.Errorf("not a wasm contract store key") - } - if !bytes.HasPrefix(key[33:], wasmContractTokenInfoKey) { - return "", fmt.Errorf("not a cw20 token_info key") - } - contractAddr := hex.EncodeToString(key[1:33]) - return contractAddr, nil -} diff --git a/tracelistener/processor/bank.go b/tracelistener/processor/bank.go index 097742a8..d757da0e 100644 --- a/tracelistener/processor/bank.go +++ b/tracelistener/processor/bank.go @@ -1,7 +1,6 @@ package processor import ( - "bytes" "sync" "go.uber.org/zap" @@ -74,7 +73,7 @@ func (b *bankProcessor) FlushCache() []tracelistener.WritebackOp { } func (b *bankProcessor) OwnsKey(key []byte) bool { - return bytes.HasPrefix(key, datamarshaler.BankKey) + return datamarshaler.IsBankBalanceKey(key) } func (b *bankProcessor) Process(data tracelistener.TraceOperation) error { diff --git a/tracelistener/processor/bank_test.go b/tracelistener/processor/bank_test.go index aae9e50d..0e0acbef 100644 --- a/tracelistener/processor/bank_test.go +++ b/tracelistener/processor/bank_test.go @@ -15,33 +15,28 @@ import ( func TestBankProcessorOwnsKey(t *testing.T) { d := bankProcessor{} tests := []struct { - name string - prefix []byte - key string - expectedErr bool + name string + key []byte + expectedOwns bool }{ { - "Correct prefix- no error", - datamarshaler.BankKey, - "key", - false, + name: "Correct prefix- no error", + key: append(datamarshaler.BankKey, []byte{1, 1, 'a', 't', 'o', 'm'}...), + expectedOwns: false, }, { - "Incorrect prefix- error", - []byte{0x0}, - "key", - true, + name: "Incorrect prefix- error", + key: []byte{0x0}, + expectedOwns: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if tt.expectedErr { - require.False(t, d.OwnsKey(append(tt.prefix, []byte(tt.key)...))) - } else { - require.True(t, d.OwnsKey(append(tt.prefix, []byte(tt.key)...))) - } + owns := d.OwnsKey(tt.key) + + require.Equal(t, tt.expectedOwns, owns) }) } } diff --git a/tracelistener/processor/cw20_balance.go b/tracelistener/processor/cw20_balance.go index e2852595..ff8f5ac0 100644 --- a/tracelistener/processor/cw20_balance.go +++ b/tracelistener/processor/cw20_balance.go @@ -7,6 +7,7 @@ import ( models "github.com/emerishq/demeris-backend-models/tracelistener" "github.com/emerishq/tracelistener/tracelistener" + "github.com/emerishq/tracelistener/tracelistener/processor/datamarshaler" "github.com/emerishq/tracelistener/tracelistener/tables" ) @@ -72,33 +73,21 @@ func (b *cw20BalanceProcessor) FlushCache() []tracelistener.WritebackOp { } func (b *cw20BalanceProcessor) OwnsKey(key []byte) bool { - _, _, err := tracelistener.SplitCW20BalanceKey(key) - return err == nil + return datamarshaler.IsCW20BalanceKey(key) } func (b *cw20BalanceProcessor) Process(data tracelistener.TraceOperation) error { b.m.Lock() defer b.m.Unlock() - contractAddr, holderAddr, err := tracelistener.SplitCW20BalanceKey(data.Key) + row, err := datamarshaler.NewDataMarshaler(b.l).CW20Balance(data) if err != nil { return err } - var ( - key = cw20BalanceCacheEntry{ - contractAddress: contractAddr, - address: holderAddr, - } - val = models.CW20BalanceRow{ - ContractAddress: contractAddr, - Address: holderAddr, - // balance trace value is the amount. - Amount: string(data.Value), - TracelistenerDatabaseRow: models.TracelistenerDatabaseRow{ - Height: data.BlockHeight, - }, - } - ) - b.heightCache[key] = val + key := cw20BalanceCacheEntry{ + contractAddress: row.ContractAddress, + address: row.Address, + } + b.heightCache[key] = row return nil } diff --git a/tracelistener/processor/cw20_token_info.go b/tracelistener/processor/cw20_token_info.go index 23c7bb0b..b093923c 100644 --- a/tracelistener/processor/cw20_token_info.go +++ b/tracelistener/processor/cw20_token_info.go @@ -1,14 +1,13 @@ package processor import ( - "encoding/json" - "fmt" "sync" "go.uber.org/zap" models "github.com/emerishq/demeris-backend-models/tracelistener" "github.com/emerishq/tracelistener/tracelistener" + "github.com/emerishq/tracelistener/tracelistener/processor/datamarshaler" "github.com/emerishq/tracelistener/tracelistener/tables" ) @@ -73,36 +72,19 @@ func (b *cw20TokenInfoProcessor) FlushCache() []tracelistener.WritebackOp { } func (b *cw20TokenInfoProcessor) OwnsKey(key []byte) bool { - _, err := tracelistener.SplitCW20TokenInfoKey(key) - return err == nil + return datamarshaler.IsCW20TokenInfoKey(key) } func (b *cw20TokenInfoProcessor) Process(data tracelistener.TraceOperation) error { b.m.Lock() defer b.m.Unlock() - contractAddr, err := tracelistener.SplitCW20TokenInfoKey(data.Key) + row, err := datamarshaler.NewDataMarshaler(b.l).CW20TokenInfo(data) if err != nil { return err } - var ( - key = cw20TokenInfoCacheEntry{ - contractAddress: contractAddr, - } - val = models.CW20TokenInfoRow{ - ContractAddress: contractAddr, - TracelistenerDatabaseRow: models.TracelistenerDatabaseRow{ - Height: data.BlockHeight, - }, - } - ) - // token_info value is a json string that contains the name, the symbol, - // the decimals and the total_supply of the token. To copy those values in - // the CW20TokenInfoRow, we can simply json.Unmarshal the value to the struct. - err = json.Unmarshal(data.Value, &val) - if err != nil { - return fmt.Errorf("unmarshal cw20 token_info value: %w", err) - } - b.heightCache[key] = val + b.heightCache[cw20TokenInfoCacheEntry{ + contractAddress: row.ContractAddress, + }] = row return nil } diff --git a/tracelistener/processor/datamarshaler/datamarshaler.go b/tracelistener/processor/datamarshaler/datamarshaler.go index d14699f0..325e4070 100644 --- a/tracelistener/processor/datamarshaler/datamarshaler.go +++ b/tracelistener/processor/datamarshaler/datamarshaler.go @@ -18,6 +18,8 @@ type Handler interface { IBCDenomTraces(data tracelistener.TraceOperation) (models.IBCDenomTraceRow, error) UnbondingDelegations(data tracelistener.TraceOperation) (models.UnbondingDelegationRow, error) Validators(data tracelistener.TraceOperation) (models.ValidatorRow, error) + CW20Balance(tracelistener.TraceOperation) (models.CW20BalanceRow, error) + CW20TokenInfo(tracelistener.TraceOperation) (models.CW20TokenInfoRow, error) } type TestHandler interface { diff --git a/tracelistener/processor/datamarshaler/impl_v42.go b/tracelistener/processor/datamarshaler/impl_v42.go index e3de3719..3c119938 100644 --- a/tracelistener/processor/datamarshaler/impl_v42.go +++ b/tracelistener/processor/datamarshaler/impl_v42.go @@ -472,3 +472,10 @@ func (d DataMarshaler) Validators(data tracelistener.TraceOperation) (models.Val }, }, nil } +func (d DataMarshaler) CW20Balance(data tracelistener.TraceOperation) (models.CW20BalanceRow, error) { + panic("CW20 balances not implemented in v0.42") +} + +func (d DataMarshaler) CW20TokenInfo(data tracelistener.TraceOperation) (models.CW20TokenInfoRow, error) { + panic("CW20 token info not implemented in v0.42") +} diff --git a/tracelistener/processor/datamarshaler/impl_v44.go b/tracelistener/processor/datamarshaler/impl_v44.go index c4b4559c..bb5c7719 100644 --- a/tracelistener/processor/datamarshaler/impl_v44.go +++ b/tracelistener/processor/datamarshaler/impl_v44.go @@ -179,7 +179,7 @@ func (d DataMarshaler) Auth(data tracelistener.TraceOperation) (models.AuthRow, func (d DataMarshaler) Delegations(data tracelistener.TraceOperation) (models.DelegationRow, error) { if data.Operation == tracelistener.DeleteOp.String() { - delegator, validator, err := tracelistener.SplitDelegationKey(data.Key) + delegator, validator, err := splitDelegationKey(data.Key) if err != nil { return models.DelegationRow{}, err } @@ -405,7 +405,7 @@ func (d DataMarshaler) UnbondingDelegations(data tracelistener.TraceOperation) ( // Our SplitDelegationKey handles (delegatorAddr, validatorAddr), and somehow the SDK people // have a func that flips the key we're handling, morphing it into something SplitDelegationKey can handle. // Thanks SDK people! - delegatorAddr, validatorAddr, err := tracelistener.SplitDelegationKey(stakingTypes.GetUBDKeyFromValIndexKey(data.Key)) + delegatorAddr, validatorAddr, err := splitDelegationKey(stakingTypes.GetUBDKeyFromValIndexKey(data.Key)) if err != nil { return models.UnbondingDelegationRow{}, fmt.Errorf("cannot parse unbonding delegation key, %w", err) } @@ -473,7 +473,7 @@ func (d DataMarshaler) Validators(data tracelistener.TraceOperation) (models.Val if data.Operation == tracelistener.DeleteOp.String() { // strip key prefix key := data.Key[1:] - rawAddress, err := tracelistener.FromLengthPrefix(key) + rawAddress, err := fromLengthPrefix(key) if err != nil { return models.ValidatorRow{}, fmt.Errorf("cannot parse length-prefixed operator address, %w", err) } @@ -540,3 +540,40 @@ func (d DataMarshaler) Validators(data tracelistener.TraceOperation) (models.Val }, }, nil } + +func (d DataMarshaler) CW20Balance(data tracelistener.TraceOperation) (models.CW20BalanceRow, error) { + contractAddr, holderAddr, err := splitCW20BalanceKey(data.Key) + if err != nil { + return models.CW20BalanceRow{}, err + } + return models.CW20BalanceRow{ + ContractAddress: contractAddr, + Address: holderAddr, + // balance trace value is the amount. + Amount: string(data.Value), + TracelistenerDatabaseRow: models.TracelistenerDatabaseRow{ + Height: data.BlockHeight, + }, + }, nil +} + +func (d DataMarshaler) CW20TokenInfo(data tracelistener.TraceOperation) (models.CW20TokenInfoRow, error) { + contractAddr, err := splitCW20TokenInfoKey(data.Key) + if err != nil { + return models.CW20TokenInfoRow{}, err + } + row := models.CW20TokenInfoRow{ + ContractAddress: contractAddr, + TracelistenerDatabaseRow: models.TracelistenerDatabaseRow{ + Height: data.BlockHeight, + }, + } + // token_info value is a json string that contains the name, the symbol, + // the decimals and the total_supply of the token. To copy those values in + // the CW20TokenInfoRow, we can simply json.Unmarshal the value to the struct. + err = json.Unmarshal(data.Value, &row) + if err != nil { + return models.CW20TokenInfoRow{}, fmt.Errorf("unmarshal cw20 token_info value: %w", err) + } + return row, nil +} diff --git a/tracelistener/processor/datamarshaler/keys.go b/tracelistener/processor/datamarshaler/keys.go new file mode 100644 index 00000000..cc0db290 --- /dev/null +++ b/tracelistener/processor/datamarshaler/keys.go @@ -0,0 +1,30 @@ +package datamarshaler + +import "fmt" + +func IsBankBalanceKey(key []byte) bool { + return isBankBalanceKey(key) +} + +func IsCW20BalanceKey(key []byte) bool { + return isCW20BalanceKey(key) +} + +func IsCW20TokenInfoKey(key []byte) bool { + return isCW20TokenInfoKey(key) +} + +// fromLengthPrefix returns the amount of data signaled by the single-byte length prefix in rawData. +func fromLengthPrefix(rawData []byte) ([]byte, error) { + if len(rawData) == 0 { + return nil, fmt.Errorf("data is nil") + } + + length := int(rawData[0]) + rawData = rawData[1:] + if len(rawData) != length { + return nil, fmt.Errorf("length prefix signals %d bytes, but total data is %d bytes long", length, len(rawData)) + } + + return rawData, nil +} diff --git a/tracelistener/processor/datamarshaler/keys_test.go b/tracelistener/processor/datamarshaler/keys_test.go new file mode 100644 index 00000000..f13c8f2b --- /dev/null +++ b/tracelistener/processor/datamarshaler/keys_test.go @@ -0,0 +1,66 @@ +package datamarshaler + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestFromLengthPrefix(t *testing.T) { + t.Parallel() + tests := []struct { + name string + rawData []byte + want []byte + wantErr bool + }{ + { + "a length-prefix works", + []byte{ + 4, // length prefix + 1, 2, 3, 4, // data + }, + []byte{1, 2, 3, 4}, + false, + }, + { + "a length-prefix with more data than anticipated", + []byte{ + 4, // length prefix + 1, 2, 3, 4, 5, // data + }, + nil, + true, + }, + { + "a length-prefix with less data than anticipated", + []byte{ + 4, // length prefix + 1, 2, 3, // data + }, + nil, + true, + }, + { + "nil rawData", + nil, + nil, + true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + res, err := fromLengthPrefix(tt.rawData) + if tt.wantErr { + require.Error(t, err) + require.Empty(t, res) + return + } + + require.NoError(t, err) + require.Equal(t, tt.want, res) + }) + } +} diff --git a/tracelistener/processor/datamarshaler/keys_v42.go b/tracelistener/processor/datamarshaler/keys_v42.go index 649fd75b..625e586a 100644 --- a/tracelistener/processor/datamarshaler/keys_v42.go +++ b/tracelistener/processor/datamarshaler/keys_v42.go @@ -3,15 +3,17 @@ package datamarshaler import ( + "bytes" + authTypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/bank/types" + bankTypes "github.com/cosmos/cosmos-sdk/x/bank/types" transferTypes "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types" host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host" stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) var ( - BankKey = types.BalancesPrefix + BankKey = bankTypes.BalancesPrefix AuthKey = authTypes.AddressStoreKeyPrefix DelegationKey = stakingTypes.DelegationKey IBCChannelKey = host.KeyChannelEndPrefix @@ -23,3 +25,15 @@ var ( UnbondingDelegationKeys = [][]byte{UnbondingDelegationKey} ) + +func isBankBalanceKey(key []byte) bool { + return bytes.HasPrefix(key, BankKey) +} + +func isCW20BalanceKey(key []byte) bool { + panic("CW20Balance not implemented in v42") +} + +func isCW20TokenInfoKey(key []byte) bool { + panic("CW20TokenInfo not implemented in v42") +} diff --git a/tracelistener/processor/datamarshaler/keys_v44.go b/tracelistener/processor/datamarshaler/keys_v44.go index 677224a7..1875273c 100644 --- a/tracelistener/processor/datamarshaler/keys_v44.go +++ b/tracelistener/processor/datamarshaler/keys_v44.go @@ -3,15 +3,21 @@ package datamarshaler import ( + "bytes" + "encoding/hex" + "fmt" + + "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32" authTypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/bank/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types" transferTypes "github.com/cosmos/ibc-go/v2/modules/apps/transfer/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) var ( - BankKey = types.BalancesPrefix + BankKey = banktypes.BalancesPrefix AuthKey = authTypes.AddressStoreKeyPrefix DelegationKey = stakingTypes.DelegationKey IBCChannelKey = host.KeyChannelEndPrefix @@ -27,3 +33,176 @@ var ( UnbondingDelegationByValidatorKey, } ) + +func isBankBalanceKey(key []byte) bool { + _, _, err := splitBalanceKey(key) + return err != nil +} + +func isCW20BalanceKey(key []byte) bool { + _, _, err := splitCW20BalanceKey(key) + return err != nil +} + +func isCW20TokenInfoKey(key []byte) bool { + _, err := splitCW20TokenInfoKey(key) + return err != nil +} + +// splitBalanceKey returns the address and the denom of a given balance key, +// or an error if it's not valid. +// param is a list of bytes. The key is a concatenation of 4 parts: +// 1. Prefix length: 1 Byte (always 03 for BalanceStorePrefix) +// 2. Address Len length: 1 Byte +// 3. Address length: From 2 +// 4. Denom length: 3 to 128 Bytes according to types.ValidateDenom +// key : +// Len 1 1 0-255 3-128 +func splitBalanceKey(key []byte) (string, string, error) { + const ( + // At-least: 1+1+0+3 + minLen = 1 + 1 + 3 + // At-maxLen : 1+1+255+128 + maxLen = 1 + 1 + 255 + 128 + ) + if len(key) < minLen || len(key) > maxLen { + return "", "", + fmt.Errorf("malformed balance key: length %d not in range %d-%d", + len(key), minLen, maxLen) + } + if !bytes.HasPrefix(key, BankKey) { + return "", "", fmt.Errorf("not a balance store key") + } + // read addr + bz, err := banktypes.AddressFromBalancesStore(key[1:]) + if err != nil { + return "", "", fmt.Errorf("balance addr: %w", err) + } + addr := hex.EncodeToString(bz) + // read denom + denom := string(key[2+len(bz):]) + if err := types.ValidateDenom(denom); err != nil { + return "", "", fmt.Errorf("balance denom: %w", err) + } + return addr, denom, nil +} + +// splitDelegationKey given a key, split it into prefix, delegator and +// validator address. +// param is a list of byte. The key is a concatenation of 5 parts, +// 1. Prefix length: 1 Byte +// 2. Delegator Address Len length: 1 Byte +// 3. Delegator Address length: From 2 +// 4. Validator Address Len length: 1 Byte +// 5. Validator Address length: From 4 +// key : +// Len 1 1 0-255 1 0-255 +// +// Note: Address len 0 does not make sense, but since in the SDK it's "possible" to +// have 0 len address for delegator/validator, we also consider empty address valid. +func splitDelegationKey(key []byte) (string, string, error) { + // At-least: 3 bytes -> 1, 2, 4 must be present. 1 byte each. + // At-max : 513 bytes -> 3 bytes from (1, 2, 4) + 510 bytes from (3, 5). + if len(key) < 3 || len(key) > (1+1+255+1+255) { + return "", "", fmt.Errorf("malformed key: length %d not in range", len(key)) + } + _, addresses := key[0], key[1:] // Strip the prefix byte. + delAddrLen := addresses[0] // Gets delegator address length + + // We have to keep this check here because this function must split the two addresses, + // FromLengthPrefix only does parsing of a well-formed length-prefix byte slice. + if len(addresses) < int(delAddrLen) { + return "", "", fmt.Errorf("delegator address should be %d bytes long, but it only has %d", delAddrLen, len(addresses)) + } + + totalPrefixedFirstAddressSz := delAddrLen + 1 // we are subslicing including the length-prefix, since FromLengthPrefix uses it + delAddrBytes, err := fromLengthPrefix(addresses[:totalPrefixedFirstAddressSz]) + if err != nil { + return "", "", fmt.Errorf("cannot parse delegator address, %w", err) + } + + delAddr := hex.EncodeToString(delAddrBytes) + + addresses = addresses[totalPrefixedFirstAddressSz:] // Subslice past the delegator address + + valAddrBytes, err := fromLengthPrefix(addresses) // We don't do any subslicing here because FromLengthPrefix will take care of parsing errors + if err != nil { + return "", "", fmt.Errorf("cannot parse validator address, %w", err) + } + + valAddr := hex.EncodeToString(valAddrBytes) + return delAddr, valAddr, nil +} + +var ( + wasmContractStorePrefix = []byte{0x03} + wasmContractBalanceKey = append([]byte{0, 7}, []byte("balance")...) + wasmContractTokenInfoKey = []byte("token_info") +) + +// splitCW20BalanceKey returns the contract and the holder address of a given +// CW20 balance key, or an error if it's not valid. +// param is a list of bytes. The key is a concatenation of 5 parts, +// 1. Prefix length: 1 Byte (always 03 for ContractStorePrefix) +// 2. Contract Address length: 32 Bytes +// 3. Type Len length: 2 Bytes +// 4. Type length: From 3 +// 5. Holder Address length: the remaining bytes +// key : +// Len 1 32 2 0-510 at least 43 +// +// Note: Address len 0 does not make sense, but since in the SDK it's "possible" to +// have 0 len address for delegator/validator, we also consider empty address valid. +func splitCW20BalanceKey(key []byte) (string, string, error) { + const ( + // At-least: 1+32+2+43 bytes + minLen = 1 + 32 + 2 + 43 + // At-maxLen : 1+32+2+510+43 bytes + maxLen = minLen + 510 + ) + if len(key) < minLen || len(key) > maxLen { + return "", "", + fmt.Errorf("malformed cw20 balance key: length %d not in range %d-%d", + len(key), minLen, maxLen) + } + if !bytes.HasPrefix(key, wasmContractStorePrefix) { + return "", "", fmt.Errorf("not a wasm contract store key") + } + if !bytes.HasPrefix(key[33:], wasmContractBalanceKey) { + return "", "", fmt.Errorf("not a cw20 balance key") + } + contractAddr := hex.EncodeToString(key[1:33]) + // holder addr must be bech32 decoded + _, bz, err := bech32.DecodeAndConvert(string(key[42:])) + if err != nil { + return "", "", fmt.Errorf("decode holder address: %w", err) + } + holderAddr := hex.EncodeToString(bz) + return contractAddr, holderAddr, nil +} + +// splitCW20TokenInfoKey returns the contract address of a given +// CW20 token_info key, or an error if it's not valid. +// param is a list of bytes. The key is a concatenation of 5 parts, +// 1. Prefix length: 1 Byte (always 03 for ContractStorePrefix) +// 2. Contract Address length: 32 Bytes +// 4. Type length: 10 Bytes (always token_info) +// key : +// Len 1 32 10 +func splitCW20TokenInfoKey(key []byte) (string, error) { + const expectedLen = 1 + 32 + 10 + if len(key) != expectedLen { + return "", fmt.Errorf( + "malformed cw20 token_info key: length %d not equal to %d", + len(key), expectedLen, + ) + } + if !bytes.HasPrefix(key, wasmContractStorePrefix) { + return "", fmt.Errorf("not a wasm contract store key") + } + if !bytes.HasPrefix(key[33:], wasmContractTokenInfoKey) { + return "", fmt.Errorf("not a cw20 token_info key") + } + contractAddr := hex.EncodeToString(key[1:33]) + return contractAddr, nil +} diff --git a/tracelistener/keys_test.go b/tracelistener/processor/datamarshaler/keys_v44_test.go similarity index 80% rename from tracelistener/keys_test.go rename to tracelistener/processor/datamarshaler/keys_v44_test.go index 45f48a31..5a91455f 100644 --- a/tracelistener/keys_test.go +++ b/tracelistener/processor/datamarshaler/keys_v44_test.go @@ -1,4 +1,6 @@ -package tracelistener +//go:build sdk_v44 + +package datamarshaler import ( "encoding/hex" @@ -60,7 +62,7 @@ func TestValidKeys(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() - da, va, err := SplitDelegationKey(tt.key) + da, va, err := splitDelegationKey(tt.key) require.NoError(t, err) require.Equal(t, da, tt.wantDelAddr) require.Equal(t, va, tt.wantValAddr) @@ -115,72 +117,13 @@ func TestInValidKeys(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - _, _, err := SplitDelegationKey(tt.key) + _, _, err := splitDelegationKey(tt.key) require.Error(t, err) require.ErrorContains(t, err, tt.errMsg) }) } } -func TestFromLengthPrefix(t *testing.T) { - t.Parallel() - tests := []struct { - name string - rawData []byte - want []byte - wantErr bool - }{ - { - "a length-prefix works", - []byte{ - 4, // length prefix - 1, 2, 3, 4, // data - }, - []byte{1, 2, 3, 4}, - false, - }, - { - "a length-prefix with more data than anticipated", - []byte{ - 4, // length prefix - 1, 2, 3, 4, 5, // data - }, - nil, - true, - }, - { - "a length-prefix with less data than anticipated", - []byte{ - 4, // length prefix - 1, 2, 3, // data - }, - nil, - true, - }, - { - "nil rawData", - nil, - nil, - true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - res, err := FromLengthPrefix(tt.rawData) - if tt.wantErr { - require.Error(t, err) - require.Empty(t, res) - return - } - - require.NoError(t, err) - require.Equal(t, tt.want, res) - }) - } -} - func TestSplitCW20BalanceKey(t *testing.T) { var ( // Reference values @@ -257,7 +200,7 @@ func TestSplitCW20BalanceKey(t *testing.T) { require := require.New(t) assert := assert.New(t) - contractAddr, holderAddr, err := SplitCW20BalanceKey(tt.key) + contractAddr, holderAddr, err := splitCW20BalanceKey(tt.key) if tt.expectedError != "" { assert.EqualError(err, tt.expectedError) @@ -328,7 +271,7 @@ func TestSplitCW20TokenInfoKey(t *testing.T) { require := require.New(t) assert := assert.New(t) - contractAddr, err := SplitCW20TokenInfoKey(tt.key) + contractAddr, err := splitCW20TokenInfoKey(tt.key) if tt.expectedError != "" { assert.EqualError(err, tt.expectedError) @@ -339,3 +282,73 @@ func TestSplitCW20TokenInfoKey(t *testing.T) { }) } } + +func TestSplitBalanceKey(t *testing.T) { + var ( + addrHexEncoded = "b1f347b54d39acd4b8b8ae571dd69ffdf45cf8c2" + addr, _ = hex.DecodeString(addrHexEncoded) + ) + tests := []struct { + name string + key []byte + expectedAddr string + expectedDenom string + expectedError string + }{ + { + name: "fail: empty key", + expectedError: "malformed balance key: length 0 not in range 5-385", + }, + { + name: "fail: key too short", + key: make([]byte, 1), + expectedError: "malformed balance key: length 1 not in range 5-385", + }, + { + name: "fail: key too long", + key: make([]byte, 386), + expectedError: "malformed balance key: length 386 not in range 5-385", + }, + { + name: "fail: key with wrong prefix", + key: []byte{0, 1, 2, 3, 4}, + expectedError: "not a balance store key", + }, + { + name: "fail: key length too big", + key: []byte{2, 255, 1, 'd', 'e', 'n', 'o', 'm'}, + expectedError: "balance addr: invalid key", + }, + { + name: "fail: invalid denom", + key: append( + append([]byte{2, uint8(len(addr))}, addr...), + []byte{'/', 'e', 'n', 'o', 'm'}...), + expectedError: "balance denom: invalid denom: /enom", + }, + { + name: "ok", + key: append( + append([]byte{2, uint8(len(addr))}, addr...), + []byte{'d', 'e', 'n', 'o', 'm'}...), + expectedAddr: addrHexEncoded, + expectedDenom: "denom", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + assert := assert.New(t) + + addr, denom, err := splitBalanceKey(tt.key) + + if tt.expectedError != "" { + require.EqualError(err, tt.expectedError) + return + } + require.NoError(err) + assert.Equal(tt.expectedAddr, addr) + assert.Equal(tt.expectedDenom, denom) + }) + } +} From 3fef96e9c39f05421ef11130173885595fae9982 Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Sat, 4 Jun 2022 11:52:05 +0200 Subject: [PATCH 2/6] fix tests --- tracelistener/processor/bank_test.go | 4 +- .../processor/cw20_balance_v42_test.go | 60 +++++++++++++++++ ...lance_test.go => cw20_balance_v44_test.go} | 3 +- .../processor/cw20_token_info_v42_test.go | 66 +++++++++++++++++++ ...fo_test.go => cw20_token_info_v44_test.go} | 3 +- .../processor/datamarshaler/keys_v42.go | 6 +- .../processor/datamarshaler/keys_v44.go | 6 +- 7 files changed, 139 insertions(+), 9 deletions(-) create mode 100644 tracelistener/processor/cw20_balance_v42_test.go rename tracelistener/processor/{cw20_balance_test.go => cw20_balance_v44_test.go} (98%) create mode 100644 tracelistener/processor/cw20_token_info_v42_test.go rename tracelistener/processor/{cw20_token_info_test.go => cw20_token_info_v44_test.go} (98%) diff --git a/tracelistener/processor/bank_test.go b/tracelistener/processor/bank_test.go index 0e0acbef..05b480a6 100644 --- a/tracelistener/processor/bank_test.go +++ b/tracelistener/processor/bank_test.go @@ -22,12 +22,12 @@ func TestBankProcessorOwnsKey(t *testing.T) { { name: "Correct prefix- no error", key: append(datamarshaler.BankKey, []byte{1, 1, 'a', 't', 'o', 'm'}...), - expectedOwns: false, + expectedOwns: true, }, { name: "Incorrect prefix- error", key: []byte{0x0}, - expectedOwns: true, + expectedOwns: false, }, } diff --git a/tracelistener/processor/cw20_balance_v42_test.go b/tracelistener/processor/cw20_balance_v42_test.go new file mode 100644 index 00000000..94465bac --- /dev/null +++ b/tracelistener/processor/cw20_balance_v42_test.go @@ -0,0 +1,60 @@ +//go:build sdk_v42 + +package processor + +import ( + "encoding/hex" + "testing" + + models "github.com/emerishq/demeris-backend-models/tracelistener" + "github.com/emerishq/tracelistener/tracelistener" + "github.com/stretchr/testify/require" +) + +func TestCW20BalanceProcessor(t *testing.T) { + var ( + balanceKey, _ = hex.DecodeString("03ade4a5f5803a439835c636395a8d648dee57b2fc90d98dc17fa887159b69638b000762616c616e63657761736d313467307339773373797965766b3366347a70327265637470646b376633757371676e35783666a") + contractAddr = "ade4a5f5803a439835c636395a8d648dee57b2fc90d98dc17fa887159b69638b" + holderAddr = "aa1f02ba302132cb453510543ce1616dbc98f200" + ) + tests := []struct { + name string + data tracelistener.TraceOperation + expectedHeightCache map[cw20BalanceCacheEntry]models.CW20BalanceRow + }{ + { + name: "ok", + data: tracelistener.TraceOperation{ + Key: balanceKey, + Value: []byte("1000"), + BlockHeight: 42, + }, + expectedHeightCache: map[cw20BalanceCacheEntry]models.CW20BalanceRow{ + { + contractAddress: contractAddr, + address: holderAddr, + }: { + ContractAddress: contractAddr, + Address: holderAddr, + Amount: "1000", + TracelistenerDatabaseRow: models.TracelistenerDatabaseRow{ + Height: 42, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + p := cw20BalanceProcessor{ + heightCache: map[cw20BalanceCacheEntry]models.CW20BalanceRow{}, + } + + // test OwnsKey + owned := p.OwnsKey(tt.data.Key) + + require.False(owned, "processor own key") + }) + } +} diff --git a/tracelistener/processor/cw20_balance_test.go b/tracelistener/processor/cw20_balance_v44_test.go similarity index 98% rename from tracelistener/processor/cw20_balance_test.go rename to tracelistener/processor/cw20_balance_v44_test.go index 23de037f..585d2f8d 100644 --- a/tracelistener/processor/cw20_balance_test.go +++ b/tracelistener/processor/cw20_balance_v44_test.go @@ -1,3 +1,5 @@ +//go:build sdk_v44 + package processor import ( @@ -63,5 +65,4 @@ func TestCW20BalanceProcessor(t *testing.T) { assert.Equal(tt.expectedHeightCache, p.heightCache) }) } - } diff --git a/tracelistener/processor/cw20_token_info_v42_test.go b/tracelistener/processor/cw20_token_info_v42_test.go new file mode 100644 index 00000000..ceafbd97 --- /dev/null +++ b/tracelistener/processor/cw20_token_info_v42_test.go @@ -0,0 +1,66 @@ +//go:build sdk_v42 + +package processor + +import ( + "encoding/hex" + "testing" + + models "github.com/emerishq/demeris-backend-models/tracelistener" + "github.com/emerishq/tracelistener/tracelistener" + "github.com/stretchr/testify/require" +) + +func TestCW20TokenInfoProcessor(t *testing.T) { + var ( + tokenInfoKey, _ = hex.DecodeString("03ade4a5f5803a439835c636395a8d648dee57b2fc90d98dc17fa887159b69638b746f6b656e5f696e666f") + contractAddr = "ade4a5f5803a439835c636395a8d648dee57b2fc90d98dc17fa887159b69638b" + tokenInfoValue = []byte(`{ + "name": "meme", + "symbol": "umeme", + "decimals": 18, + "total_supply": "169420" +}`) + ) + tests := []struct { + name string + data tracelistener.TraceOperation + expectedHeightCache map[cw20TokenInfoCacheEntry]models.CW20TokenInfoRow + }{ + { + name: "ok", + data: tracelistener.TraceOperation{ + Key: tokenInfoKey, + Value: tokenInfoValue, + BlockHeight: 42, + }, + expectedHeightCache: map[cw20TokenInfoCacheEntry]models.CW20TokenInfoRow{ + { + contractAddress: contractAddr, + }: { + ContractAddress: contractAddr, + Name: "meme", + Symbol: "umeme", + Decimals: 18, + TotalSupply: "169420", + TracelistenerDatabaseRow: models.TracelistenerDatabaseRow{ + Height: 42, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + p := cw20TokenInfoProcessor{ + heightCache: map[cw20TokenInfoCacheEntry]models.CW20TokenInfoRow{}, + } + + // test OwnsKey + owned := p.OwnsKey(tt.data.Key) + + require.False(owned, "processor own key") + }) + } +} diff --git a/tracelistener/processor/cw20_token_info_test.go b/tracelistener/processor/cw20_token_info_v44_test.go similarity index 98% rename from tracelistener/processor/cw20_token_info_test.go rename to tracelistener/processor/cw20_token_info_v44_test.go index c2ba392f..13f874d0 100644 --- a/tracelistener/processor/cw20_token_info_test.go +++ b/tracelistener/processor/cw20_token_info_v44_test.go @@ -1,3 +1,5 @@ +//go:build sdk_v44 + package processor import ( @@ -69,5 +71,4 @@ func TestCW20TokenInfoProcessor(t *testing.T) { assert.Equal(tt.expectedHeightCache, p.heightCache) }) } - } diff --git a/tracelistener/processor/datamarshaler/keys_v42.go b/tracelistener/processor/datamarshaler/keys_v42.go index 625e586a..a3c8eb42 100644 --- a/tracelistener/processor/datamarshaler/keys_v42.go +++ b/tracelistener/processor/datamarshaler/keys_v42.go @@ -31,9 +31,11 @@ func isBankBalanceKey(key []byte) bool { } func isCW20BalanceKey(key []byte) bool { - panic("CW20Balance not implemented in v42") + // CW20Balance not implemented in v42 + return false } func isCW20TokenInfoKey(key []byte) bool { - panic("CW20TokenInfo not implemented in v42") + // CW20TokenInfo not implemented in v42 + return false } diff --git a/tracelistener/processor/datamarshaler/keys_v44.go b/tracelistener/processor/datamarshaler/keys_v44.go index 1875273c..c7f8bc02 100644 --- a/tracelistener/processor/datamarshaler/keys_v44.go +++ b/tracelistener/processor/datamarshaler/keys_v44.go @@ -36,17 +36,17 @@ var ( func isBankBalanceKey(key []byte) bool { _, _, err := splitBalanceKey(key) - return err != nil + return err == nil } func isCW20BalanceKey(key []byte) bool { _, _, err := splitCW20BalanceKey(key) - return err != nil + return err == nil } func isCW20TokenInfoKey(key []byte) bool { _, err := splitCW20TokenInfoKey(key) - return err != nil + return err == nil } // splitBalanceKey returns the address and the denom of a given balance key, From 8aa53e96fe7912993e5dcb0786e5d86dcd334ee6 Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Tue, 7 Jun 2022 13:22:20 +0200 Subject: [PATCH 3/6] remove unused lint error with sdk_v42 build tag --- tracelistener/processor/datamarshaler/keys.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracelistener/processor/datamarshaler/keys.go b/tracelistener/processor/datamarshaler/keys.go index cc0db290..748e6f13 100644 --- a/tracelistener/processor/datamarshaler/keys.go +++ b/tracelistener/processor/datamarshaler/keys.go @@ -15,7 +15,7 @@ func IsCW20TokenInfoKey(key []byte) bool { } // fromLengthPrefix returns the amount of data signaled by the single-byte length prefix in rawData. -func fromLengthPrefix(rawData []byte) ([]byte, error) { +func fromLengthPrefix(rawData []byte) ([]byte, error) { //nolint:unused if len(rawData) == 0 { return nil, fmt.Errorf("data is nil") } From 7255ffd033210d47ef382d5e9b110e2d3bd9f654 Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Tue, 7 Jun 2022 14:26:26 +0200 Subject: [PATCH 4/6] test: add cases for iris trace --- tracelistener/processor/bank_test.go | 17 +++++++++++++++-- .../processor/datamarshaler/impl_v44_test.go | 3 ++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/tracelistener/processor/bank_test.go b/tracelistener/processor/bank_test.go index 05b480a6..891a780c 100644 --- a/tracelistener/processor/bank_test.go +++ b/tracelistener/processor/bank_test.go @@ -1,6 +1,7 @@ package processor import ( + "encoding/json" "testing" "github.com/stretchr/testify/require" @@ -14,21 +15,33 @@ import ( func TestBankProcessorOwnsKey(t *testing.T) { d := bankProcessor{} + + // Setup a case for an iris trace that was interpreted as a bank trace + irisTrace := []byte("{\"operation\":\"write\",\"key\":\"AhT+5cRMA/vuTTyGA9Qqcf/L5yTzpA==\",\"value\":\"CiQKBXVpcmlzEhs1MDk2MjUxNDM1MDYwNjM3ODgwNTA2Nzg0NTU=\",\"metadata\":{\"blockHeight\":15065683,\"txHash\":\"31647EB774FDC743E067FA459AA05CD5B0F315431CCCA54F98D877D7C26BCFC4\"}}") + var irisTraceOperation tracelistener.TraceOperation + err := json.Unmarshal(irisTrace, &irisTraceOperation) + require.NoError(t, err) + tests := []struct { name string key []byte expectedOwns bool }{ { - name: "Correct prefix- no error", + name: "ok", key: append(datamarshaler.BankKey, []byte{1, 1, 'a', 't', 'o', 'm'}...), expectedOwns: true, }, { - name: "Incorrect prefix- error", + name: "fail: incorrect prefix", key: []byte{0x0}, expectedOwns: false, }, + { + name: "fail: not a bank balance trace", + key: irisTraceOperation.Key, + expectedOwns: false, + }, } for _, tt := range tests { diff --git a/tracelistener/processor/datamarshaler/impl_v44_test.go b/tracelistener/processor/datamarshaler/impl_v44_test.go index c125b250..b2785643 100644 --- a/tracelistener/processor/datamarshaler/impl_v44_test.go +++ b/tracelistener/processor/datamarshaler/impl_v44_test.go @@ -23,6 +23,7 @@ func TestDataMarshalerBank(t *testing.T) { } coinBz, _ = coins.Marshal() ) + tests := []struct { name string tr tracelistener.TraceOperation @@ -54,7 +55,7 @@ func TestDataMarshalerBank(t *testing.T) { expectedError: "invalid balance coin: invalid denom: ", }, { - name: "ok: value is not a valid coin", + name: "fail: value is not a valid coin", tr: tracelistener.TraceOperation{ Operation: tracelistener.WriteOp.String(), Key: append(types.BalancesPrefix, []byte{3, 'a', 'd', 'd'}...), From acb0c76b400d9fcf556f7e1eca04620c2233d8b8 Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Tue, 7 Jun 2022 14:29:48 +0200 Subject: [PATCH 5/6] lint: disable again --- tracelistener/processor/datamarshaler/keys.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracelistener/processor/datamarshaler/keys.go b/tracelistener/processor/datamarshaler/keys.go index 748e6f13..d1991785 100644 --- a/tracelistener/processor/datamarshaler/keys.go +++ b/tracelistener/processor/datamarshaler/keys.go @@ -15,7 +15,7 @@ func IsCW20TokenInfoKey(key []byte) bool { } // fromLengthPrefix returns the amount of data signaled by the single-byte length prefix in rawData. -func fromLengthPrefix(rawData []byte) ([]byte, error) { //nolint:unused +func fromLengthPrefix(rawData []byte) ([]byte, error) { //nolint:deadcode if len(rawData) == 0 { return nil, fmt.Errorf("data is nil") } From b05e010e095d4ddb566211653c074ae3b8b09c7d Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Tue, 7 Jun 2022 14:37:18 +0200 Subject: [PATCH 6/6] fix formatting in sdk_v42 --- tracelistener/processor/datamarshaler/keys_v42.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tracelistener/processor/datamarshaler/keys_v42.go b/tracelistener/processor/datamarshaler/keys_v42.go index a3c8eb42..bf600756 100644 --- a/tracelistener/processor/datamarshaler/keys_v42.go +++ b/tracelistener/processor/datamarshaler/keys_v42.go @@ -32,10 +32,10 @@ func isBankBalanceKey(key []byte) bool { func isCW20BalanceKey(key []byte) bool { // CW20Balance not implemented in v42 - return false + return false } func isCW20TokenInfoKey(key []byte) bool { // CW20TokenInfo not implemented in v42 - return false + return false }