From 5ccfc5312c0f867567b198f5a67cb9eb83094909 Mon Sep 17 00:00:00 2001 From: Collin Brittain Date: Fri, 4 Aug 2023 15:02:47 -0500 Subject: [PATCH] Order contract call signing --- module/x/gravity/keeper/contract_call.go | 36 ++++++++++++++++++------ orchestrator/cosmos_gravity/src/query.rs | 13 ++++++++- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/module/x/gravity/keeper/contract_call.go b/module/x/gravity/keeper/contract_call.go index 1369b8a3b..a1618c610 100644 --- a/module/x/gravity/keeper/contract_call.go +++ b/module/x/gravity/keeper/contract_call.go @@ -3,6 +3,7 @@ package keeper import ( "bytes" "encoding/hex" + "sort" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -11,30 +12,31 @@ import ( func (k Keeper) GetUnsignedContractCallTxs(ctx sdk.Context, val sdk.ValAddress) []*types.ContractCallTx { var unconfirmed []*types.ContractCallTx - k.IterateOutgoingTxsByType(ctx, types.ContractCallTxPrefixByte, func(_ []byte, otx types.OutgoingTx) bool { - sig := k.getEthereumSignature(ctx, otx.GetStoreIndex(), val) + k.IterateCompletedOutgoingTxsByType(ctx, types.ContractCallTxPrefixByte, func(_ []byte, cotx types.OutgoingTx) bool { + sig := k.getEthereumSignature(ctx, cotx.GetStoreIndex(), val) if len(sig) == 0 { - call, ok := otx.(*types.ContractCallTx) + call, ok := cotx.(*types.ContractCallTx) if !ok { - panic(sdkerrors.Wrapf(types.ErrInvalid, "couldn't cast to contract call for %s", otx)) + panic(sdkerrors.Wrapf(types.ErrInvalid, "couldn't cast to contract call for completed tx %s", cotx)) } unconfirmed = append(unconfirmed, call) } return false }) - k.IterateCompletedOutgoingTxsByType(ctx, types.ContractCallTxPrefixByte, func(_ []byte, cotx types.OutgoingTx) bool { - sig := k.getEthereumSignature(ctx, cotx.GetStoreIndex(), val) + + k.IterateOutgoingTxsByType(ctx, types.ContractCallTxPrefixByte, func(_ []byte, otx types.OutgoingTx) bool { + sig := k.getEthereumSignature(ctx, otx.GetStoreIndex(), val) if len(sig) == 0 { - call, ok := cotx.(*types.ContractCallTx) + call, ok := otx.(*types.ContractCallTx) if !ok { - panic(sdkerrors.Wrapf(types.ErrInvalid, "couldn't cast to contract call for completed tx %s", cotx)) + panic(sdkerrors.Wrapf(types.ErrInvalid, "couldn't cast to contract call for %s", otx)) } unconfirmed = append(unconfirmed, call) } return false }) - return unconfirmed + return orderContractCallsByAddressAndNonceAscending(unconfirmed) } func (k Keeper) contractCallExecuted(ctx sdk.Context, invalidationScope []byte, invalidationNonce uint64) { @@ -64,3 +66,19 @@ func (k Keeper) contractCallExecuted(ctx sdk.Context, invalidationScope []byte, k.CompleteOutgoingTx(ctx, completedCallTx) } + +// orderContractCallsByAddressAndNonceAscending sorts a slice of contract calls by address and nonce in ascending order +func orderContractCallsByAddressAndNonceAscending(calls []*types.ContractCallTx) []*types.ContractCallTx { + sort.SliceStable(calls, func(i, j int) bool { + // Compare the addresses first + addrComparison := bytes.Compare(calls[i].InvalidationScope, calls[j].InvalidationScope) + if addrComparison != 0 { + return addrComparison < 0 + } + + // If the addresses are equal, compare the nonces + return calls[i].InvalidationNonce < calls[j].InvalidationNonce + }) + + return calls +} diff --git a/orchestrator/cosmos_gravity/src/query.rs b/orchestrator/cosmos_gravity/src/query.rs index 07734849a..0dbf558a5 100644 --- a/orchestrator/cosmos_gravity/src/query.rs +++ b/orchestrator/cosmos_gravity/src/query.rs @@ -1,3 +1,5 @@ +use std::cmp::Ordering; + use deep_space::address::Address; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; @@ -196,7 +198,16 @@ pub async fn get_oldest_unsigned_logic_call( address: address.to_string(), }) .await?; - let calls = request.into_inner().calls; + let mut calls = request.into_inner().calls; + // sort by scope then nonce ascending + calls.sort_by(|a, b| { + let scope_cmp = a.invalidation_scope.cmp(&b.invalidation_scope); + if scope_cmp == Ordering::Equal { + a.invalidation_nonce.cmp(&b.invalidation_nonce) + } else { + scope_cmp + } + }); let mut out = Vec::new(); for call in calls { out.push(LogicCall::from_proto(call)?)