Skip to content

Commit

Permalink
feat(evm): genesis import&export for events and confirmedEventQueue (#…
Browse files Browse the repository at this point in the history
…1408)

* feat(evm): genesis import&export for events and confirmedEventQueue

* address comments in queuer
  • Loading branch information
fish-sammy committed Apr 5, 2022
1 parent 7439d13 commit 7444ef7
Show file tree
Hide file tree
Showing 15 changed files with 1,259 additions and 321 deletions.
89 changes: 71 additions & 18 deletions docs/proto/proto-docs.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion proto/evm/v1beta1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ syntax = "proto3";
package evm.v1beta1;
option go_package = "github.com/axelarnetwork/axelar-core/x/evm/types";

import "utils/v1beta1/queuer.proto";
import "gogoproto/gogo.proto";
import "evm/v1beta1/params.proto";
import "evm/v1beta1/types.proto";
Expand All @@ -15,7 +16,7 @@ message GenesisState {
message Chain {
Params params = 1 [ (gogoproto.nullable) = false ];
repeated BurnerInfo burner_infos = 2 [ (gogoproto.nullable) = false ];
map<string, Command> command_queue = 3 [ (gogoproto.nullable) = false ];
utils.v1beta1.QueueState command_queue = 3 [ (gogoproto.nullable) = false ];
repeated ERC20Deposit confirmed_deposits = 4
[ (gogoproto.nullable) = false ];
repeated ERC20Deposit burned_deposits = 5 [ (gogoproto.nullable) = false ];
Expand All @@ -25,6 +26,9 @@ message GenesisState {

Gateway gateway = 9 [ (gogoproto.nullable) = false ];
repeated ERC20TokenMetadata tokens = 10 [ (gogoproto.nullable) = false ];
repeated Event events = 11 [ (gogoproto.nullable) = false ];
utils.v1beta1.QueueState confirmed_event_queue = 12
[ (gogoproto.nullable) = false ];
}

repeated Chain chains = 3 [ (gogoproto.nullable) = false ];
Expand Down
17 changes: 17 additions & 0 deletions proto/utils/v1beta1/queuer.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
syntax = "proto3";
package utils.v1beta1;

option go_package = "github.com/axelarnetwork/axelar-core/utils";

import "gogoproto/gogo.proto";

option (gogoproto.goproto_getters_all) = false;

message QueueState {
message Item {
bytes key = 1;
bytes value = 2;
}

map<string, Item> items = 1 [ (gogoproto.nullable) = false ];
}
5 changes: 5 additions & 0 deletions testutils/rand/rand.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,3 +325,8 @@ func Context(store types.MultiStore) sdk.Context {
ctx.GasMeter().ConsumeGas(uint64(I64Between(1000, 1000000)), "test")
return ctx
}

// Of returns a random item from the given slice
func Of[T any](items ...T) T {
return items[I64Between(0, int64(len(items)))]
}
67 changes: 60 additions & 7 deletions utils/queuer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package utils
import (
"encoding/binary"
"fmt"
"strings"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -99,17 +100,69 @@ func (q GeneralKVQueue) Keys() []Key {
return keys
}

// ImportState should only be used to populate state at genesis. Panics if the given state is invalid
func (q GeneralKVQueue) ImportState(state map[string]codec.ProtoMarshaler, validator ...func(map[string]codec.ProtoMarshaler) error) {
if len(validator) > 0 {
if err := validator[0](state); err != nil {
panic(err)
// ExportState exports the given queue's state from the kv store
func (q GeneralKVQueue) ExportState() (state QueueState) {
state.Items = make(map[string]QueueState_Item)

iter := sdk.KVStorePrefixIterator(q.store.KVStore, q.name.AsKey())
defer CloseLogError(iter, q.logger)

for ; iter.Valid(); iter.Next() {
var key gogoprototypes.BytesValue
q.store.cdc.MustUnmarshalLengthPrefixed(iter.Value(), &key)

item := QueueState_Item{
Key: key.Value,
Value: q.store.GetRaw(KeyFromBz(key.Value)),
}

state.Items[string(iter.Key())] = item
}

return state
}

// ImportState imports the given queue state into the kv store
func (q GeneralKVQueue) ImportState(state QueueState) {
name := string(q.name.AsKey())
for key, item := range state.Items {
if !strings.HasPrefix(key, fmt.Sprintf("%s%s", name, DefaultDelimiter)) {
panic(fmt.Errorf("queue key %s is invalid for queue %s", key, name))
}

q.store.Set(KeyFromStr(key), &gogoprototypes.BytesValue{Value: item.Key})
q.store.SetRaw(KeyFromBz(item.Key), item.Value)
}
}

// ValidateBasic returns an error if the given queue state is invalid
func (m QueueState) ValidateBasic(queueName ...string) error {
itemKeySeen := make(map[string]bool)
for key, item := range m.Items {
if itemKeySeen[string(item.Key)] {
return fmt.Errorf("duplicate item key")
}

if len(key) == 0 {
return fmt.Errorf("queue key cannot be empty")
}

if len(queueName) > 0 && !strings.HasPrefix(key, fmt.Sprintf("%s%s", queueName[0], DefaultDelimiter)) {
return fmt.Errorf("queue key %s is invalid for queue %s", key, queueName[0])
}

if len(item.Key) == 0 {
return fmt.Errorf("item key cannot be empty")
}

for key, value := range state {
q.store.Set(q.name.AppendStr(key), value)
if len(item.Value) == 0 {
return fmt.Errorf("item value cannot be empty")
}

itemKeySeen[string(item.Key)] = true
}

return nil
}

// BlockHeightKVQueue is a queue that orders items with the block height at which the items are enqueued;
Expand Down

0 comments on commit 7444ef7

Please sign in to comment.