From c2da67db92f8d1f00dc4525b2e05aa4e09e6d28e Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Tue, 6 Aug 2024 14:22:13 -0700 Subject: [PATCH 01/23] Bump avalanchego to master --- go.mod | 4 +-- go.sum | 8 ++--- params/config.go | 6 ++-- params/network_upgrades.go | 7 +++-- peer/network_test.go | 3 +- plugin/evm/syncervm_test.go | 5 ++-- plugin/evm/tx_gossip_test.go | 16 +++++----- plugin/evm/vm_test.go | 17 ++++++----- plugin/evm/vm_upgrade_bytes_test.go | 9 +++--- plugin/evm/vm_warp_test.go | 5 ++-- precompile/contracts/warp/predicate_test.go | 7 +++-- scripts/versions.sh | 2 +- tests/load/load_test.go | 2 ++ tests/warp/warp_test.go | 33 ++++++++++++++------- utils/snow.go | 4 +-- 15 files changed, 76 insertions(+), 52 deletions(-) diff --git a/go.mod b/go.mod index 7956a35752..7a5de639cd 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21.12 require ( github.com/VictoriaMetrics/fastcache v1.12.1 - github.com/ava-labs/avalanchego v1.11.11-0.20240729205337-a0f7e422bb84 + github.com/ava-labs/avalanchego v1.11.11-0.20240805202431-479145a6602d github.com/cespare/cp v0.1.0 github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 github.com/davecgh/go-spew v1.1.1 @@ -54,7 +54,7 @@ require ( require ( github.com/DataDog/zstd v1.5.2 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect - github.com/ava-labs/coreth v0.13.7 // indirect + github.com/ava-labs/coreth v0.13.8-0.20240802110637-b3e5088d062d // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect diff --git a/go.sum b/go.sum index a33e68a2f1..549db74bb0 100644 --- a/go.sum +++ b/go.sum @@ -56,10 +56,10 @@ github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/ava-labs/avalanchego v1.11.11-0.20240729205337-a0f7e422bb84 h1:AmPZLlnVREbJ/viK/hDTIVn1bqX8QTB2CFtrBxHwnsw= -github.com/ava-labs/avalanchego v1.11.11-0.20240729205337-a0f7e422bb84/go.mod h1:POgZPryqe80OeHCDNrXrPOKoFre736iFuMgmUBeKaLc= -github.com/ava-labs/coreth v0.13.7 h1:k8T9u/ROifl8f7oXjHRc1KvSISRl9txvy7gGVmHEz6g= -github.com/ava-labs/coreth v0.13.7/go.mod h1:tXDujonxXFOF6oK5HS2EmgtSXJK3Gy6RpZxb5WzR9rM= +github.com/ava-labs/avalanchego v1.11.11-0.20240805202431-479145a6602d h1:T8sDX5uo7zSEjwDtVccS1WtzuC3pRXs9NXYbmGGagJ4= +github.com/ava-labs/avalanchego v1.11.11-0.20240805202431-479145a6602d/go.mod h1:9e0UPXJboybmgFjeTj+SFbK4ugbrdG4t68VdiUW5oQ8= +github.com/ava-labs/coreth v0.13.8-0.20240802110637-b3e5088d062d h1:klPTcKVvqfA2KSKaRvQAO56Pd4XAqGhwgMTQ6/W+w7w= +github.com/ava-labs/coreth v0.13.8-0.20240802110637-b3e5088d062d/go.mod h1:tXDujonxXFOF6oK5HS2EmgtSXJK3Gy6RpZxb5WzR9rM= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= diff --git a/params/config.go b/params/config.go index 59ae91a869..356b208f2e 100644 --- a/params/config.go +++ b/params/config.go @@ -33,8 +33,8 @@ import ( "math/big" "time" + "github.com/ava-labs/avalanchego/upgrade" "github.com/ava-labs/avalanchego/utils/constants" - "github.com/ava-labs/avalanchego/version" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" @@ -57,7 +57,7 @@ var ( DynamicFeeExtraDataSize = 80 RollupWindow uint64 = 10 - DefaultGenesisTime = version.DefaultUpgradeTime + DefaultGenesisTime = time.Date(2020, time.December, 5, 5, 0, 0, 0, time.UTC) DefaultFeeConfig = commontype.FeeConfig{ GasLimit: big.NewInt(8_000_000), @@ -110,7 +110,7 @@ var ( PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0), - CancunTime: utils.TimeToNewUint64(version.GetEUpgradeTime(constants.UnitTestID)), + CancunTime: utils.TimeToNewUint64(upgrade.GetConfig(constants.UnitTestID).EtnaTime), NetworkUpgrades: getDefaultNetworkUpgrades(constants.UnitTestID), GenesisPrecompiles: Precompiles{}, UpgradeConfig: UpgradeConfig{}, diff --git a/params/network_upgrades.go b/params/network_upgrades.go index 7dcf15e911..013367c947 100644 --- a/params/network_upgrades.go +++ b/params/network_upgrades.go @@ -7,7 +7,7 @@ import ( "fmt" "reflect" - "github.com/ava-labs/avalanchego/version" + "github.com/ava-labs/avalanchego/upgrade" "github.com/ava-labs/subnet-evm/utils" ) @@ -143,10 +143,11 @@ func (n *NetworkUpgrades) GetAvalancheRules(time uint64) AvalancheRules { // getDefaultNetworkUpgrades returns the network upgrades for the specified network ID. // These should not return nil values. func getDefaultNetworkUpgrades(networkID uint32) NetworkUpgrades { + agoUpgrade := upgrade.GetConfig(networkID) return NetworkUpgrades{ SubnetEVMTimestamp: utils.NewUint64(0), - DurangoTimestamp: utils.TimeToNewUint64(version.GetDurangoTime(networkID)), - EUpgradeTimestamp: utils.TimeToNewUint64(version.GetEUpgradeTime(networkID)), + DurangoTimestamp: utils.TimeToNewUint64(agoUpgrade.DurangoTime), + EUpgradeTimestamp: utils.TimeToNewUint64(agoUpgrade.EtnaTime), } } diff --git a/peer/network_test.go b/peer/network_test.go index 89419314cc..2ebcf6775a 100644 --- a/peer/network_test.go +++ b/peer/network_test.go @@ -14,6 +14,7 @@ import ( "github.com/ava-labs/avalanchego/network/p2p" "github.com/ava-labs/avalanchego/snow/engine/common" + "github.com/ava-labs/avalanchego/snow/engine/enginetest" "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/set" ethcommon "github.com/ethereum/go-ethereum/common" @@ -510,7 +511,7 @@ func TestHandleInvalidMessages(t *testing.T) { nodeID := ids.GenerateTestNodeID() requestID := uint32(1) - sender := &common.SenderTest{ + sender := &enginetest.Sender{ SendAppErrorF: func(context.Context, ids.NodeID, uint32, int32, string) error { return nil }, diff --git a/plugin/evm/syncervm_test.go b/plugin/evm/syncervm_test.go index a81474c072..533740666b 100644 --- a/plugin/evm/syncervm_test.go +++ b/plugin/evm/syncervm_test.go @@ -20,6 +20,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" commonEng "github.com/ava-labs/avalanchego/snow/engine/common" + "github.com/ava-labs/avalanchego/snow/engine/enginetest" "github.com/ava-labs/avalanchego/snow/engine/snowman/block" "github.com/ava-labs/avalanchego/utils/set" @@ -124,7 +125,7 @@ func TestStateSyncToggleEnabledToDisabled(t *testing.T) { test.expectedErr = nil syncDisabledVM := &VM{} - appSender := &commonEng.SenderTest{T: t} + appSender := &enginetest.Sender{T: t} appSender.SendAppGossipF = func(context.Context, commonEng.SendConfig, []byte) error { return nil } appSender.SendAppRequestF = func(ctx context.Context, nodeSet set.Set[ids.NodeID], requestID uint32, request []byte) error { nodeID, hasItem := nodeSet.Pop() @@ -368,7 +369,7 @@ func createSyncServerAndClientVMs(t *testing.T, test syncTest, numBlocks int) *s // off of a server VM. type syncVMSetup struct { serverVM *VM - serverAppSender *commonEng.SenderTest + serverAppSender *enginetest.Sender fundedAccounts map[*keystore.Key]*types.StateAccount diff --git a/plugin/evm/tx_gossip_test.go b/plugin/evm/tx_gossip_test.go index 1f04e223ce..36c47ffde5 100644 --- a/plugin/evm/tx_gossip_test.go +++ b/plugin/evm/tx_gossip_test.go @@ -18,7 +18,9 @@ import ( "github.com/ava-labs/avalanchego/proto/pb/sdk" "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/snow/engine/common" + "github.com/ava-labs/avalanchego/snow/engine/enginetest" "github.com/ava-labs/avalanchego/snow/validators" + "github.com/ava-labs/avalanchego/snow/validators/validatorstest" agoUtils "github.com/ava-labs/avalanchego/utils" "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/set" @@ -35,10 +37,10 @@ func TestEthTxGossip(t *testing.T) { require := require.New(t) ctx := context.Background() snowCtx := utils.TestSnowContext() - validatorState := &validators.TestState{} + validatorState := &validatorstest.State{} snowCtx.ValidatorState = validatorState - responseSender := &common.FakeSender{ + responseSender := &enginetest.SenderStub{ SentAppResponse: make(chan []byte, 1), } vm := &VM{ @@ -54,7 +56,7 @@ func TestEthTxGossip(t *testing.T) { nil, make(chan common.Message), nil, - &common.SenderTest{}, + &enginetest.Sender{}, )) require.NoError(vm.SetState(ctx, snow.NormalOp)) @@ -63,7 +65,7 @@ func TestEthTxGossip(t *testing.T) { }() // sender for the peer requesting gossip from [vm] - peerSender := &common.FakeSender{ + peerSender := &enginetest.SenderStub{ SentAppRequest: make(chan []byte, 1), } @@ -153,7 +155,7 @@ func TestEthTxPushGossipOutbound(t *testing.T) { require := require.New(t) ctx := context.Background() snowCtx := utils.TestSnowContext() - snowCtx.ValidatorState = &validators.TestState{ + snowCtx.ValidatorState = &validatorstest.State{ GetCurrentHeightF: func(context.Context) (uint64, error) { return 0, nil }, @@ -161,7 +163,7 @@ func TestEthTxPushGossipOutbound(t *testing.T) { return nil, nil }, } - sender := &common.FakeSender{ + sender := &enginetest.SenderStub{ SentAppGossip: make(chan []byte, 1), } @@ -217,7 +219,7 @@ func TestEthTxPushGossipInbound(t *testing.T) { ctx := context.Background() snowCtx := utils.TestSnowContext() - sender := &common.SenderTest{} + sender := &enginetest.Sender{} vm := &VM{ ethTxPullGossiper: gossip.NoOpGossiper{}, } diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 2a0e5849c2..758fbbfd1d 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -33,7 +33,8 @@ import ( "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/snow/consensus/snowman" commonEng "github.com/ava-labs/avalanchego/snow/engine/common" - "github.com/ava-labs/avalanchego/snow/validators" + "github.com/ava-labs/avalanchego/snow/engine/enginetest" + "github.com/ava-labs/avalanchego/snow/validators/validatorstest" avalancheConstants "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/formatting" @@ -152,7 +153,7 @@ func NewContext() *snow.Context { _ = aliaser.Alias(testCChainID, testCChainID.String()) _ = aliaser.Alias(testXChainID, "X") _ = aliaser.Alias(testXChainID, testXChainID.String()) - ctx.ValidatorState = &validators.TestState{ + ctx.ValidatorState = &validatorstest.State{ GetSubnetIDF: func(_ context.Context, chainID ids.ID) (ids.ID, error) { subnetID, ok := map[ids.ID]ids.ID{ avalancheConstants.PlatformChainID: avalancheConstants.PrimaryNetworkID, @@ -221,13 +222,15 @@ func GenesisVM(t *testing.T, genesisJSON string, configJSON string, upgradeJSON string, -) (chan commonEng.Message, - *VM, database.Database, - *commonEng.SenderTest, +) ( + chan commonEng.Message, + *VM, + database.Database, + *enginetest.Sender, ) { vm := &VM{} ctx, dbManager, genesisBytes, issuer, _ := setupGenesis(t, genesisJSON) - appSender := &commonEng.SenderTest{T: t} + appSender := &enginetest.Sender{T: t} appSender.CantSendAppGossip = true appSender.SendAppGossipF = func(context.Context, commonEng.SendConfig, []byte) error { return nil } err := vm.Initialize( @@ -1934,7 +1937,7 @@ func TestConfigureLogLevel(t *testing.T) { t.Run(test.name, func(t *testing.T) { vm := &VM{} ctx, dbManager, genesisBytes, issuer, _ := setupGenesis(t, test.genesisJSON) - appSender := &commonEng.SenderTest{T: t} + appSender := &enginetest.Sender{T: t} appSender.CantSendAppGossip = true appSender.SendAppGossipF = func(context.Context, commonEng.SendConfig, []byte) error { return nil } err := vm.Initialize( diff --git a/plugin/evm/vm_upgrade_bytes_test.go b/plugin/evm/vm_upgrade_bytes_test.go index 6b0d4ad7a4..85d8d84885 100644 --- a/plugin/evm/vm_upgrade_bytes_test.go +++ b/plugin/evm/vm_upgrade_bytes_test.go @@ -14,7 +14,8 @@ import ( "github.com/ava-labs/avalanchego/snow" commonEng "github.com/ava-labs/avalanchego/snow/engine/common" - "github.com/ava-labs/avalanchego/version" + "github.com/ava-labs/avalanchego/snow/engine/enginetest" + "github.com/ava-labs/avalanchego/upgrade" "github.com/ava-labs/avalanchego/vms/components/chain" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/types" @@ -32,7 +33,7 @@ import ( ) var ( - DefaultEUpgradeTime = uint64(version.GetEUpgradeTime(testNetworkID).Unix()) + DefaultEUpgradeTime = uint64(upgrade.GetConfig(testNetworkID).EtnaTime.Unix()) ) func TestVMUpgradeBytesPrecompile(t *testing.T) { @@ -183,7 +184,7 @@ func TestNetworkUpgradesOverriden(t *testing.T) { vm := &VM{} ctx, dbManager, genesisBytes, issuer, _ := setupGenesis(t, string(genesisBytes)) - appSender := &commonEng.SenderTest{T: t} + appSender := &enginetest.Sender{T: t} appSender.CantSendAppGossip = true appSender.SendAppGossipF = func(context.Context, commonEng.SendConfig, []byte) error { return nil } err = vm.Initialize( @@ -212,7 +213,7 @@ func TestNetworkUpgradesOverriden(t *testing.T) { require.False(t, vm.chainConfig.IsSubnetEVM(0)) require.True(t, vm.chainConfig.IsSubnetEVM(2)) require.False(t, vm.chainConfig.IsDurango(0)) - require.False(t, vm.chainConfig.IsDurango(uint64(version.DefaultUpgradeTime.Unix()))) + require.False(t, vm.chainConfig.IsDurango(uint64(params.DefaultGenesisTime.Unix()))) require.True(t, vm.chainConfig.IsDurango(1607144402)) } diff --git a/plugin/evm/vm_warp_test.go b/plugin/evm/vm_warp_test.go index d90826a158..d5c46e540c 100644 --- a/plugin/evm/vm_warp_test.go +++ b/plugin/evm/vm_warp_test.go @@ -15,6 +15,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/engine/snowman/block" "github.com/ava-labs/avalanchego/snow/validators" + "github.com/ava-labs/avalanchego/snow/validators/validatorstest" avagoUtils "github.com/ava-labs/avalanchego/utils" "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/set" @@ -278,7 +279,7 @@ func testWarpVMTransaction(t *testing.T, unsignedMessage *avalancheWarp.Unsigned minimumValidPChainHeight := uint64(10) getValidatorSetTestErr := errors.New("can't get validator set test error") - vm.ctx.ValidatorState = &validators.TestState{ + vm.ctx.ValidatorState = &validatorstest.State{ // TODO: test both Primary Network / C-Chain and non-Primary Network GetSubnetIDF: func(ctx context.Context, chainID ids.ID) (ids.ID, error) { return ids.Empty, nil @@ -448,7 +449,7 @@ func TestReceiveWarpMessage(t *testing.T) { minimumValidPChainHeight := uint64(10) getValidatorSetTestErr := errors.New("can't get validator set test error") - vm.ctx.ValidatorState = &validators.TestState{ + vm.ctx.ValidatorState = &validatorstest.State{ GetSubnetIDF: func(ctx context.Context, chainID ids.ID) (ids.ID, error) { return ids.Empty, nil }, diff --git a/precompile/contracts/warp/predicate_test.go b/precompile/contracts/warp/predicate_test.go index 2b293b97a9..113db6fc43 100644 --- a/precompile/contracts/warp/predicate_test.go +++ b/precompile/contracts/warp/predicate_test.go @@ -13,6 +13,7 @@ import ( "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/snow/engine/snowman/block" "github.com/ava-labs/avalanchego/snow/validators" + "github.com/ava-labs/avalanchego/snow/validators/validatorstest" agoUtils "github.com/ava-labs/avalanchego/utils" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/bls" @@ -197,7 +198,7 @@ func createSnowCtx(validatorRanges []validatorRange) *snow.Context { } snowCtx := utils.TestSnowContext() - state := &validators.TestState{ + state := &validatorstest.State{ GetSubnetIDF: func(ctx context.Context, chainID ids.ID) (ids.ID, error) { return sourceSubnetID, nil }, @@ -266,7 +267,7 @@ func TestWarpMessageFromPrimaryNetwork(t *testing.T) { snowCtx.ChainID = ids.GenerateTestID() snowCtx.CChainID = cChainID snowCtx.NetworkID = networkID - snowCtx.ValidatorState = &validators.TestState{ + snowCtx.ValidatorState = &validatorstest.State{ GetSubnetIDF: func(ctx context.Context, chainID ids.ID) (ids.ID, error) { require.Equal(chainID, cChainID) return constants.PrimaryNetworkID, nil // Return Primary Network SubnetID @@ -666,7 +667,7 @@ func initWarpPredicateTests() { snowCtx := utils.TestSnowContext() snowCtx.NetworkID = networkID - state := &validators.TestState{ + state := &validatorstest.State{ GetSubnetIDF: func(ctx context.Context, chainID ids.ID) (ids.ID, error) { return sourceSubnetID, nil }, diff --git a/scripts/versions.sh b/scripts/versions.sh index 4bb7ec71b9..a1bcaf654f 100644 --- a/scripts/versions.sh +++ b/scripts/versions.sh @@ -4,7 +4,7 @@ # shellcheck disable=SC2034 # Don't export them as they're used in the context of other calls -AVALANCHE_VERSION=${AVALANCHE_VERSION:-'v1.11.10'} +AVALANCHE_VERSION=${AVALANCHE_VERSION:-'479145a6602dfc6263c3d7842d26d7c7be7d5991'} GINKGO_VERSION=${GINKGO_VERSION:-'v2.2.0'} # This won't be used, but it's here to make code syncs easier diff --git a/tests/load/load_test.go b/tests/load/load_test.go index c8f80915c4..aa5a14783b 100644 --- a/tests/load/load_test.go +++ b/tests/load/load_test.go @@ -53,10 +53,12 @@ var _ = ginkgo.Describe("[Load Simulator]", ginkgo.Ordered, func() { var env *e2e.TestEnvironment ginkgo.BeforeAll(func() { + tc := e2e.NewTestContext() genesisPath := filepath.Join(repoRootPath, "tests/load/genesis/genesis.json") nodes := utils.NewTmpnetNodes(nodeCount) env = e2e.NewTestEnvironment( + tc, flagVars, utils.NewTmpnetNetwork( "subnet-evm-small-load", diff --git a/tests/warp/warp_test.go b/tests/warp/warp_test.go index 54f27a47fc..57567ae451 100644 --- a/tests/warp/warp_test.go +++ b/tests/warp/warp_test.go @@ -91,9 +91,11 @@ func TestE2E(t *testing.T) { var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { // Run only once in the first ginkgo process + tc := e2e.NewTestContext() nodes := utils.NewTmpnetNodes(tmpnet.DefaultNodeCount) env := e2e.NewTestEnvironment( + tc, flagVars, utils.NewTmpnetNetwork( "subnet-evm-warp-e2e", @@ -109,13 +111,14 @@ var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { // Run in every ginkgo process require := require.New(ginkgo.GinkgoT()) + tc := e2e.NewTestContext() // Initialize the local test environment from the global state if len(envBytes) > 0 { - e2e.InitSharedTestEnvironment(envBytes) + e2e.InitSharedTestEnvironment(ginkgo.GinkgoT(), envBytes) } - network := e2e.Env.GetNetwork() + network := e2e.GetEnv(tc).GetNetwork() // By default all nodes are validating all subnets validatorURIs := make([]string, len(network.Nodes)) @@ -142,7 +145,7 @@ var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { } infoClient := info.NewClient(network.Nodes[0].URI) - cChainBlockchainID, err := infoClient.GetBlockchainID(e2e.DefaultContext(), "C") + cChainBlockchainID, err := infoClient.GetBlockchainID(tc.DefaultContext(), "C") require.NoError(err) cChainSubnetDetails = &Subnet{ @@ -155,7 +158,8 @@ var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { var _ = ginkgo.Describe("[Warp]", func() { testFunc := func(sendingSubnet *Subnet, receivingSubnet *Subnet) { - w := newWarpTest(e2e.DefaultContext(), sendingSubnet, receivingSubnet) + tc := e2e.NewTestContext() + w := newWarpTest(tc.DefaultContext(), sendingSubnet, receivingSubnet) log.Info("Sending message from A to B") w.sendMessageFromSendingSubnet() @@ -294,7 +298,8 @@ func (w *warpTest) getBlockHashAndNumberFromTxReceipt(ctx context.Context, clien } func (w *warpTest) sendMessageFromSendingSubnet() { - ctx := e2e.DefaultContext() + tc := e2e.NewTestContext() + ctx := tc.DefaultContext() require := require.New(ginkgo.GinkgoT()) client := w.sendingSubnetClients[0] @@ -375,7 +380,8 @@ func (w *warpTest) sendMessageFromSendingSubnet() { func (w *warpTest) aggregateSignaturesViaAPI() { require := require.New(ginkgo.GinkgoT()) - ctx := e2e.DefaultContext() + tc := e2e.NewTestContext() + ctx := tc.DefaultContext() warpAPIs := make(map[ids.NodeID]warpBackend.Client, len(w.sendingSubnetURIs)) for _, uri := range w.sendingSubnetURIs { @@ -434,7 +440,8 @@ func (w *warpTest) aggregateSignaturesViaAPI() { func (w *warpTest) aggregateSignatures() { require := require.New(ginkgo.GinkgoT()) - ctx := e2e.DefaultContext() + tc := e2e.NewTestContext() + ctx := tc.DefaultContext() // Verify that the signature aggregation matches the results of manually constructing the warp message client, err := warpBackend.NewClient(w.sendingSubnetURIs[0], w.sendingSubnet.BlockchainID.String()) @@ -457,7 +464,8 @@ func (w *warpTest) aggregateSignatures() { func (w *warpTest) deliverAddressedCallToReceivingSubnet() { require := require.New(ginkgo.GinkgoT()) - ctx := e2e.DefaultContext() + tc := e2e.NewTestContext() + ctx := tc.DefaultContext() client := w.receivingSubnetClients[0] log.Info("Subscribing to new heads") @@ -511,7 +519,8 @@ func (w *warpTest) deliverAddressedCallToReceivingSubnet() { func (w *warpTest) deliverBlockHashPayload() { require := require.New(ginkgo.GinkgoT()) - ctx := e2e.DefaultContext() + tc := e2e.NewTestContext() + ctx := tc.DefaultContext() client := w.receivingSubnetClients[0] log.Info("Subscribing to new heads") @@ -565,7 +574,8 @@ func (w *warpTest) deliverBlockHashPayload() { func (w *warpTest) executeHardHatTest() { require := require.New(ginkgo.GinkgoT()) - ctx := e2e.DefaultContext() + tc := e2e.NewTestContext() + ctx := tc.DefaultContext() client := w.sendingSubnetClients[0] log.Info("Subscribing to new heads") @@ -593,7 +603,8 @@ func (w *warpTest) executeHardHatTest() { func (w *warpTest) warpLoad() { require := require.New(ginkgo.GinkgoT()) - ctx := e2e.DefaultContext() + tc := e2e.NewTestContext() + ctx := tc.DefaultContext() var ( numWorkers = len(w.sendingSubnetClients) diff --git a/utils/snow.go b/utils/snow.go index 96c13708d3..92a1d236c1 100644 --- a/utils/snow.go +++ b/utils/snow.go @@ -7,7 +7,7 @@ import ( "github.com/ava-labs/avalanchego/api/metrics" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" - "github.com/ava-labs/avalanchego/snow/validators" + "github.com/ava-labs/avalanchego/snow/validators/validatorstest" "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/logging" ) @@ -28,6 +28,6 @@ func TestSnowContext() *snow.Context { BCLookup: ids.NewAliaser(), Metrics: metrics.NewMultiGatherer(), ChainDataDir: "", - ValidatorState: &validators.TestState{}, + ValidatorState: &validatorstest.State{}, } } From 33466ce39e99fc9d2da7d1f0b7cc7c7817046617 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Tue, 6 Aug 2024 16:22:04 -0700 Subject: [PATCH 02/23] always sign uptime messages (testing branch) --- go.mod | 2 +- go.sum | 4 +- plugin/evm/vm.go | 1 + plugin/evm/vm_warp_test.go | 6 +-- warp/backend.go | 54 +++++++++++++++++-- warp/backend_test.go | 12 ++--- warp/handlers/signature_request.go | 2 +- warp/handlers/signature_request_p2p.go | 20 ++++--- warp/handlers/signature_request_p2p_test.go | 4 +- warp/handlers/signature_request_test.go | 4 +- warp/handlers/validator_uptime_handler.go | 38 +++++++++++++ .../handlers/validator_uptime_handler_test.go | 35 ++++++++++++ warp/service.go | 2 +- 13 files changed, 154 insertions(+), 30 deletions(-) create mode 100644 warp/handlers/validator_uptime_handler.go create mode 100644 warp/handlers/validator_uptime_handler_test.go diff --git a/go.mod b/go.mod index 7a5de639cd..77f454cf97 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21.12 require ( github.com/VictoriaMetrics/fastcache v1.12.1 - github.com/ava-labs/avalanchego v1.11.11-0.20240805202431-479145a6602d + github.com/ava-labs/avalanchego v1.11.11-0.20240806190314-3e244010896c github.com/cespare/cp v0.1.0 github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 github.com/davecgh/go-spew v1.1.1 diff --git a/go.sum b/go.sum index 549db74bb0..7a9622bc39 100644 --- a/go.sum +++ b/go.sum @@ -56,8 +56,8 @@ github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/ava-labs/avalanchego v1.11.11-0.20240805202431-479145a6602d h1:T8sDX5uo7zSEjwDtVccS1WtzuC3pRXs9NXYbmGGagJ4= -github.com/ava-labs/avalanchego v1.11.11-0.20240805202431-479145a6602d/go.mod h1:9e0UPXJboybmgFjeTj+SFbK4ugbrdG4t68VdiUW5oQ8= +github.com/ava-labs/avalanchego v1.11.11-0.20240806190314-3e244010896c h1:cORLkxcmTX41CRH5ugc+hd+GphyxNnDU1Qy4ShaP3rY= +github.com/ava-labs/avalanchego v1.11.11-0.20240806190314-3e244010896c/go.mod h1:9e0UPXJboybmgFjeTj+SFbK4ugbrdG4t68VdiUW5oQ8= github.com/ava-labs/coreth v0.13.8-0.20240802110637-b3e5088d062d h1:klPTcKVvqfA2KSKaRvQAO56Pd4XAqGhwgMTQ6/W+w7w= github.com/ava-labs/coreth v0.13.8-0.20240802110637-b3e5088d062d/go.mod h1:tXDujonxXFOF6oK5HS2EmgtSXJK3Gy6RpZxb5WzR9rM= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index ad380630e4..b12c99128e 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -497,6 +497,7 @@ func (vm *VM) Initialize( if err != nil { return err } + vm.warpBackend.AddMessageValidator(&handlers.ValidatorUptimeHandler{}) // clear warpdb on initialization if config enabled if vm.config.PruneWarpDB { diff --git a/plugin/evm/vm_warp_test.go b/plugin/evm/vm_warp_test.go index d5c46e540c..16f9893d6f 100644 --- a/plugin/evm/vm_warp_test.go +++ b/plugin/evm/vm_warp_test.go @@ -112,7 +112,7 @@ func TestSendWarpMessage(t *testing.T) { unsignedMessageID := unsignedMessage.ID() // Verify the signature cannot be fetched before the block is accepted - _, err = vm.warpBackend.GetMessageSignature(unsignedMessageID) + _, err = vm.warpBackend.GetMessageSignatureByID(unsignedMessageID) require.Error(err) _, err = vm.warpBackend.GetBlockSignature(blk.ID()) require.Error(err) @@ -122,7 +122,7 @@ func TestSendWarpMessage(t *testing.T) { vm.blockChain.DrainAcceptorQueue() // Verify the message signature after accepting the block. - rawSignatureBytes, err := vm.warpBackend.GetMessageSignature(unsignedMessageID) + rawSignatureBytes, err := vm.warpBackend.GetMessageSignatureByID(unsignedMessageID) require.NoError(err) blsSignature, err := bls.SignatureFromBytes(rawSignatureBytes[:]) require.NoError(err) @@ -595,7 +595,7 @@ func TestMessageSignatureRequestsToVM(t *testing.T) { // Add the known message and get its signature to confirm. err = vm.warpBackend.AddMessage(warpMessage) require.NoError(t, err) - signature, err := vm.warpBackend.GetMessageSignature(warpMessage.ID()) + signature, err := vm.warpBackend.GetMessageSignatureByID(warpMessage.ID()) require.NoError(t, err) tests := map[string]struct { diff --git a/warp/backend.go b/warp/backend.go index 7e7377ad57..59b6283bd0 100644 --- a/warp/backend.go +++ b/warp/backend.go @@ -30,14 +30,28 @@ type BlockClient interface { GetAcceptedBlock(ctx context.Context, blockID ids.ID) (snowman.Block, error) } +type MessageValidator interface { + // If the validator returns nil, the message is considered valid and the + // backend will sign it. + ValidateMessage(*avalancheWarp.UnsignedMessage) error +} + // Backend tracks signature-eligible warp messages and provides an interface to fetch them. // The backend is also used to query for warp message signatures by the signature request handler. type Backend interface { // AddMessage signs [unsignedMessage] and adds it to the warp backend database AddMessage(unsignedMessage *avalancheWarp.UnsignedMessage) error - // GetMessageSignature returns the signature of the requested message hash. - GetMessageSignature(messageID ids.ID) ([bls.SignatureLen]byte, error) + // AddMessageValidator adds a validator to the backend. The backend will sign + // messages that pass any of the validators, in addition to those known in the db. + AddMessageValidator(validator MessageValidator) + + // GetMessageSignatureByID returns the signature of the requested message. + GetMessageSignature(message *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) + + // GetMessageSignatureByID returns the signature of the requested message hash. + // TODO: should we deprecate this method? + GetMessageSignatureByID(messageID ids.ID) ([bls.SignatureLen]byte, error) // GetBlockSignature returns the signature of the requested message hash. GetBlockSignature(blockID ids.ID) ([bls.SignatureLen]byte, error) @@ -62,6 +76,7 @@ type backend struct { blockSignatureCache *cache.LRU[ids.ID, [bls.SignatureLen]byte] messageCache *cache.LRU[ids.ID, *avalancheWarp.UnsignedMessage] offchainAddressedCallMsgs map[ids.ID]*avalancheWarp.UnsignedMessage + messageValidators []MessageValidator } // NewBackend creates a new Backend, and initializes the signature cache and message tracking database. @@ -88,6 +103,10 @@ func NewBackend( return b, b.initOffChainMessages(offchainMessages) } +func (b *backend) AddMessageValidator(validator MessageValidator) { + b.messageValidators = append(b.messageValidators, validator) +} + func (b *backend) initOffChainMessages(offchainMessages [][]byte) error { for i, offchainMsg := range offchainMessages { unsignedMsg, err := avalancheWarp.ParseUnsignedMessage(offchainMsg) @@ -142,15 +161,23 @@ func (b *backend) AddMessage(unsignedMessage *avalancheWarp.UnsignedMessage) err return nil } -func (b *backend) GetMessageSignature(messageID ids.ID) ([bls.SignatureLen]byte, error) { +func (b *backend) GetMessageSignature(unsignedMessage *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) { + messageID := unsignedMessage.ID() + log.Debug("Getting warp message from backend", "messageID", messageID) if sig, ok := b.messageSignatureCache.Get(messageID); ok { return sig, nil } - unsignedMessage, err := b.GetMessage(messageID) + var err error + for _, v := range append(b.messageValidators, b) { + err := v.ValidateMessage(unsignedMessage) + if err == nil { + break + } + } if err != nil { - return [bls.SignatureLen]byte{}, fmt.Errorf("failed to get warp message %s from db: %w", messageID.String(), err) + return [bls.SignatureLen]byte{}, fmt.Errorf("failed to validate warp message: %w", err) } var signature [bls.SignatureLen]byte @@ -164,6 +191,23 @@ func (b *backend) GetMessageSignature(messageID ids.ID) ([bls.SignatureLen]byte, return signature, nil } +func (b *backend) ValidateMessage(unsignedMessage *avalancheWarp.UnsignedMessage) error { + messageID := unsignedMessage.ID() + _, err := b.GetMessage(messageID) + if err != nil { + return fmt.Errorf("failed to get warp message %s from db: %w", messageID.String(), err) + } + return nil +} + +func (b *backend) GetMessageSignatureByID(messageID ids.ID) ([bls.SignatureLen]byte, error) { + unsignedMessage, err := b.GetMessage(messageID) + if err != nil { + return [bls.SignatureLen]byte{}, fmt.Errorf("failed to get warp message %s: %w", messageID, err) + } + return b.GetMessageSignature(unsignedMessage) +} + func (b *backend) GetBlockSignature(blockID ids.ID) ([bls.SignatureLen]byte, error) { log.Debug("Getting block from backend", "blockID", blockID) if sig, ok := b.blockSignatureCache.Get(blockID); ok { diff --git a/warp/backend_test.go b/warp/backend_test.go index a262d760ef..789b73aa74 100644 --- a/warp/backend_test.go +++ b/warp/backend_test.go @@ -60,7 +60,7 @@ func TestClearDB(t *testing.T) { err = backend.AddMessage(unsignedMsg) require.NoError(t, err) // ensure that the message was added - _, err = backend.GetMessageSignature(messageID) + _, err = backend.GetMessageSignatureByID(messageID) require.NoError(t, err) } @@ -75,7 +75,7 @@ func TestClearDB(t *testing.T) { // ensure all messages have been deleted for _, messageID := range messageIDs { - _, err := backend.GetMessageSignature(messageID) + _, err := backend.GetMessageSignatureByID(messageID) require.ErrorContains(t, err, "failed to get warp message") } } @@ -95,7 +95,7 @@ func TestAddAndGetValidMessage(t *testing.T) { // Verify that a signature is returned successfully, and compare to expected signature. messageID := testUnsignedMessage.ID() - signature, err := backend.GetMessageSignature(messageID) + signature, err := backend.GetMessageSignatureByID(messageID) require.NoError(t, err) expectedSig, err := warpSigner.Sign(testUnsignedMessage) @@ -114,7 +114,7 @@ func TestAddAndGetUnknownMessage(t *testing.T) { // Try getting a signature for a message that was not added. messageID := testUnsignedMessage.ID() - _, err = backend.GetMessageSignature(messageID) + _, err = backend.GetMessageSignatureByID(messageID) require.Error(t, err) } @@ -163,7 +163,7 @@ func TestZeroSizedCache(t *testing.T) { // Verify that a signature is returned successfully, and compare to expected signature. messageID := testUnsignedMessage.ID() - signature, err := backend.GetMessageSignature(messageID) + signature, err := backend.GetMessageSignatureByID(messageID) require.NoError(t, err) expectedSig, err := warpSigner.Sign(testUnsignedMessage) @@ -192,7 +192,7 @@ func TestOffChainMessages(t *testing.T) { require.NoError(err) require.Equal(testUnsignedMessage.Bytes(), msg.Bytes()) - signature, err := b.GetMessageSignature(testUnsignedMessage.ID()) + signature, err := b.GetMessageSignatureByID(testUnsignedMessage.ID()) require.NoError(err) expectedSignatureBytes, err := warpSigner.Sign(msg) require.NoError(err) diff --git a/warp/handlers/signature_request.go b/warp/handlers/signature_request.go index cab7914243..25374de1ee 100644 --- a/warp/handlers/signature_request.go +++ b/warp/handlers/signature_request.go @@ -45,7 +45,7 @@ func (s *SignatureRequestHandler) OnMessageSignatureRequest(ctx context.Context, s.stats.UpdateMessageSignatureRequestTime(time.Since(startTime)) }() - signature, err := s.backend.GetMessageSignature(signatureRequest.MessageID) + signature, err := s.backend.GetMessageSignatureByID(signatureRequest.MessageID) if err != nil { log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) s.stats.IncMessageSignatureMiss() diff --git a/warp/handlers/signature_request_p2p.go b/warp/handlers/signature_request_p2p.go index ecc72305af..227aaa1a31 100644 --- a/warp/handlers/signature_request_p2p.go +++ b/warp/handlers/signature_request_p2p.go @@ -28,6 +28,10 @@ const ( ErrFailedToMarshal ) +type AddressedCallHandler interface { + GetMessageSignature(*avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) +} + // SignatureRequestHandlerP2P serves warp signature requests using the p2p // framework from avalanchego. It is a peer.RequestHandler for // message.MessageSignatureRequest. @@ -35,6 +39,8 @@ type SignatureRequestHandlerP2P struct { backend warp.Backend codec codec.Manager stats *handlerStats + + addressedPayloadHandlers []AddressedCallHandler } func NewSignatureRequestHandlerP2P(backend warp.Backend, codec codec.Manager) *SignatureRequestHandlerP2P { @@ -45,6 +51,10 @@ func NewSignatureRequestHandlerP2P(backend warp.Backend, codec codec.Manager) *S } } +func (s *SignatureRequestHandlerP2P) AddAddressedCallHandler(handler AddressedCallHandler) { + s.addressedPayloadHandlers = append(s.addressedPayloadHandlers, handler) +} + func (s *SignatureRequestHandlerP2P) AppRequest( ctx context.Context, nodeID ids.NodeID, @@ -79,11 +89,7 @@ func (s *SignatureRequestHandlerP2P) AppRequest( var sig [bls.SignatureLen]byte switch p := parsed.(type) { case *payload.AddressedCall: - // Note we pass the unsigned message ID to GetMessageSignature since - // that is what the backend expects. - // However, we verify the types and format of the payload to ensure - // the message conforms to the ACP-118 spec. - sig, err = s.GetMessageSignature(unsignedMessage.ID()) + sig, err = s.GetMessageSignature(unsignedMessage) if err != nil { s.stats.IncMessageSignatureMiss() } else { @@ -122,7 +128,7 @@ func (s *SignatureRequestHandlerP2P) AppRequest( return respBytes, nil } -func (s *SignatureRequestHandlerP2P) GetMessageSignature(messageID ids.ID) ([bls.SignatureLen]byte, error) { +func (s *SignatureRequestHandlerP2P) GetMessageSignature(message *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) { startTime := time.Now() s.stats.IncMessageSignatureRequest() @@ -131,7 +137,7 @@ func (s *SignatureRequestHandlerP2P) GetMessageSignature(messageID ids.ID) ([bls s.stats.UpdateMessageSignatureRequestTime(time.Since(startTime)) }() - return s.backend.GetMessageSignature(messageID) + return s.backend.GetMessageSignature(message) } func (s *SignatureRequestHandlerP2P) GetBlockSignature(blockID ids.ID) ([bls.SignatureLen]byte, error) { diff --git a/warp/handlers/signature_request_p2p_test.go b/warp/handlers/signature_request_p2p_test.go index 1f8f9530cb..677eb6e1f9 100644 --- a/warp/handlers/signature_request_p2p_test.go +++ b/warp/handlers/signature_request_p2p_test.go @@ -44,9 +44,9 @@ func TestMessageSignatureHandlerP2P(t *testing.T) { require.NoError(t, err) messageID := msg.ID() require.NoError(t, backend.AddMessage(msg)) - signature, err := backend.GetMessageSignature(messageID) + signature, err := backend.GetMessageSignatureByID(messageID) require.NoError(t, err) - offchainSignature, err := backend.GetMessageSignature(offchainMessage.ID()) + offchainSignature, err := backend.GetMessageSignatureByID(offchainMessage.ID()) require.NoError(t, err) unknownPayload, err := payload.NewAddressedCall([]byte{0, 0, 0}, []byte("unknown message")) diff --git a/warp/handlers/signature_request_test.go b/warp/handlers/signature_request_test.go index 172f182c96..e723a50f86 100644 --- a/warp/handlers/signature_request_test.go +++ b/warp/handlers/signature_request_test.go @@ -38,9 +38,9 @@ func TestMessageSignatureHandler(t *testing.T) { require.NoError(t, err) messageID := msg.ID() require.NoError(t, backend.AddMessage(msg)) - signature, err := backend.GetMessageSignature(messageID) + signature, err := backend.GetMessageSignatureByID(messageID) require.NoError(t, err) - offchainSignature, err := backend.GetMessageSignature(offchainMessage.ID()) + offchainSignature, err := backend.GetMessageSignatureByID(offchainMessage.ID()) require.NoError(t, err) unknownMessageID := ids.GenerateTestID() diff --git a/warp/handlers/validator_uptime_handler.go b/warp/handlers/validator_uptime_handler.go new file mode 100644 index 0000000000..8f488b07fe --- /dev/null +++ b/warp/handlers/validator_uptime_handler.go @@ -0,0 +1,38 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package handlers + +import ( + "errors" + "fmt" + + avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" + "github.com/ava-labs/avalanchego/vms/platformvm/warp/messages" + "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + "github.com/ethereum/go-ethereum/log" +) + +var errInvalidRequest = errors.New("invalid request") + +type ValidatorUptimeHandler struct{} + +func (v *ValidatorUptimeHandler) ValidateMessage(unsignedMessage *avalancheWarp.UnsignedMessage) error { + parsed, err := payload.ParseAddressedCall(unsignedMessage.Payload) + if err != nil { + return fmt.Errorf("failed to parse payload: %w", err) + } + // TODO: Does nil/empty SourceAddress matter? + if len(parsed.SourceAddress) != 0 { + return errInvalidRequest + } + + vdr, err := messages.ParseValidatorUptime(parsed.Payload) + if err != nil { + return fmt.Errorf("failed to parse validator uptime message: %w", err) + } + + log.Info("Received validator uptime message", "validationID", vdr.ValidationID, "totalUptime", vdr.TotalUptime) + log.Warn("Signing validator uptime message by default, not production behavior", "validationID", vdr.ValidationID, "totalUptime", vdr.TotalUptime) + return nil +} diff --git a/warp/handlers/validator_uptime_handler_test.go b/warp/handlers/validator_uptime_handler_test.go new file mode 100644 index 0000000000..d2a094c150 --- /dev/null +++ b/warp/handlers/validator_uptime_handler_test.go @@ -0,0 +1,35 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package handlers + +import ( + "testing" + + "github.com/ava-labs/avalanchego/ids" + avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" + "github.com/ava-labs/avalanchego/vms/platformvm/warp/messages" + "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + "github.com/stretchr/testify/require" +) + +func TestValidatorUptimeHandler(t *testing.T) { + require := require.New(t) + + v := &ValidatorUptimeHandler{} + + validationID := ids.GenerateTestID() + totalUptime := uint64(1_000_000) // arbitrary value + vdrUptime, err := messages.NewValidatorUptime(validationID, totalUptime) + require.NoError(err) + + addressedCall, err := payload.NewAddressedCall(nil, vdrUptime.Bytes()) + require.NoError(err) + + networkID := uint32(0) + sourceChain := ids.Empty + message, err := avalancheWarp.NewUnsignedMessage(networkID, sourceChain, addressedCall.Bytes()) + require.NoError(err) + + require.NoError(v.ValidateMessage(message)) +} diff --git a/warp/service.go b/warp/service.go index 2bd310f38d..64c0200c78 100644 --- a/warp/service.go +++ b/warp/service.go @@ -51,7 +51,7 @@ func (a *API) GetMessage(ctx context.Context, messageID ids.ID) (hexutil.Bytes, // GetMessageSignature returns the BLS signature associated with a messageID. func (a *API) GetMessageSignature(ctx context.Context, messageID ids.ID) (hexutil.Bytes, error) { - signature, err := a.backend.GetMessageSignature(messageID) + signature, err := a.backend.GetMessageSignatureByID(messageID) if err != nil { return nil, fmt.Errorf("failed to get signature for message %s with error %w", messageID, err) } From 964e19390e356f87197c6e9ed0e3d07483f182b6 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Tue, 6 Aug 2024 16:24:19 -0700 Subject: [PATCH 03/23] nits --- warp/backend.go | 2 +- warp/handlers/signature_request_p2p.go | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/warp/backend.go b/warp/backend.go index 59b6283bd0..b747f1418b 100644 --- a/warp/backend.go +++ b/warp/backend.go @@ -46,7 +46,7 @@ type Backend interface { // messages that pass any of the validators, in addition to those known in the db. AddMessageValidator(validator MessageValidator) - // GetMessageSignatureByID returns the signature of the requested message. + // GetMessageSignature returns the signature of the requested message. GetMessageSignature(message *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) // GetMessageSignatureByID returns the signature of the requested message hash. diff --git a/warp/handlers/signature_request_p2p.go b/warp/handlers/signature_request_p2p.go index 227aaa1a31..4fede3da33 100644 --- a/warp/handlers/signature_request_p2p.go +++ b/warp/handlers/signature_request_p2p.go @@ -39,8 +39,6 @@ type SignatureRequestHandlerP2P struct { backend warp.Backend codec codec.Manager stats *handlerStats - - addressedPayloadHandlers []AddressedCallHandler } func NewSignatureRequestHandlerP2P(backend warp.Backend, codec codec.Manager) *SignatureRequestHandlerP2P { @@ -51,10 +49,6 @@ func NewSignatureRequestHandlerP2P(backend warp.Backend, codec codec.Manager) *S } } -func (s *SignatureRequestHandlerP2P) AddAddressedCallHandler(handler AddressedCallHandler) { - s.addressedPayloadHandlers = append(s.addressedPayloadHandlers, handler) -} - func (s *SignatureRequestHandlerP2P) AppRequest( ctx context.Context, nodeID ids.NodeID, From a5cde373560812c1e2fce60df2955a307dccce92 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Tue, 6 Aug 2024 16:34:44 -0700 Subject: [PATCH 04/23] cleanup --- plugin/evm/vm_warp_test.go | 7 +++---- warp/backend.go | 12 ----------- warp/backend_test.go | 23 ++++++++------------- warp/handlers/signature_request.go | 9 +++++++- warp/handlers/signature_request_p2p_test.go | 5 ++--- warp/handlers/signature_request_test.go | 4 ++-- warp/service.go | 6 +++++- 7 files changed, 29 insertions(+), 37 deletions(-) diff --git a/plugin/evm/vm_warp_test.go b/plugin/evm/vm_warp_test.go index 16f9893d6f..93e1e97778 100644 --- a/plugin/evm/vm_warp_test.go +++ b/plugin/evm/vm_warp_test.go @@ -109,10 +109,9 @@ func TestSendWarpMessage(t *testing.T) { logData := receipts[0].Logs[0].Data unsignedMessage, err := warp.UnpackSendWarpEventDataToMessage(logData) require.NoError(err) - unsignedMessageID := unsignedMessage.ID() // Verify the signature cannot be fetched before the block is accepted - _, err = vm.warpBackend.GetMessageSignatureByID(unsignedMessageID) + _, err = vm.warpBackend.GetMessageSignature(unsignedMessage) require.Error(err) _, err = vm.warpBackend.GetBlockSignature(blk.ID()) require.Error(err) @@ -122,7 +121,7 @@ func TestSendWarpMessage(t *testing.T) { vm.blockChain.DrainAcceptorQueue() // Verify the message signature after accepting the block. - rawSignatureBytes, err := vm.warpBackend.GetMessageSignatureByID(unsignedMessageID) + rawSignatureBytes, err := vm.warpBackend.GetMessageSignature(unsignedMessage) require.NoError(err) blsSignature, err := bls.SignatureFromBytes(rawSignatureBytes[:]) require.NoError(err) @@ -595,7 +594,7 @@ func TestMessageSignatureRequestsToVM(t *testing.T) { // Add the known message and get its signature to confirm. err = vm.warpBackend.AddMessage(warpMessage) require.NoError(t, err) - signature, err := vm.warpBackend.GetMessageSignatureByID(warpMessage.ID()) + signature, err := vm.warpBackend.GetMessageSignature(warpMessage) require.NoError(t, err) tests := map[string]struct { diff --git a/warp/backend.go b/warp/backend.go index b747f1418b..f8558b5195 100644 --- a/warp/backend.go +++ b/warp/backend.go @@ -49,10 +49,6 @@ type Backend interface { // GetMessageSignature returns the signature of the requested message. GetMessageSignature(message *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) - // GetMessageSignatureByID returns the signature of the requested message hash. - // TODO: should we deprecate this method? - GetMessageSignatureByID(messageID ids.ID) ([bls.SignatureLen]byte, error) - // GetBlockSignature returns the signature of the requested message hash. GetBlockSignature(blockID ids.ID) ([bls.SignatureLen]byte, error) @@ -200,14 +196,6 @@ func (b *backend) ValidateMessage(unsignedMessage *avalancheWarp.UnsignedMessage return nil } -func (b *backend) GetMessageSignatureByID(messageID ids.ID) ([bls.SignatureLen]byte, error) { - unsignedMessage, err := b.GetMessage(messageID) - if err != nil { - return [bls.SignatureLen]byte{}, fmt.Errorf("failed to get warp message %s: %w", messageID, err) - } - return b.GetMessageSignature(unsignedMessage) -} - func (b *backend) GetBlockSignature(blockID ids.ID) ([bls.SignatureLen]byte, error) { log.Debug("Getting block from backend", "blockID", blockID) if sig, ok := b.blockSignatureCache.Get(blockID); ok { diff --git a/warp/backend_test.go b/warp/backend_test.go index 789b73aa74..756e5f48a4 100644 --- a/warp/backend_test.go +++ b/warp/backend_test.go @@ -10,7 +10,6 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils" "github.com/ava-labs/avalanchego/utils/crypto/bls" - "github.com/ava-labs/avalanchego/utils/hashing" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" "github.com/ava-labs/subnet-evm/warp/warptest" @@ -49,18 +48,17 @@ func TestClearDB(t *testing.T) { // use multiple messages to test that all messages get cleared payloads := [][]byte{[]byte("test1"), []byte("test2"), []byte("test3"), []byte("test4"), []byte("test5")} - messageIDs := []ids.ID{} + messages := make([]*avalancheWarp.UnsignedMessage, 0, len(payloads)) // add all messages for _, payload := range payloads { unsignedMsg, err := avalancheWarp.NewUnsignedMessage(networkID, sourceChainID, payload) require.NoError(t, err) - messageID := hashing.ComputeHash256Array(unsignedMsg.Bytes()) - messageIDs = append(messageIDs, messageID) + messages = append(messages, unsignedMsg) err = backend.AddMessage(unsignedMsg) require.NoError(t, err) // ensure that the message was added - _, err = backend.GetMessageSignatureByID(messageID) + _, err = backend.GetMessageSignature(unsignedMsg) require.NoError(t, err) } @@ -74,8 +72,8 @@ func TestClearDB(t *testing.T) { require.False(t, it.Next()) // ensure all messages have been deleted - for _, messageID := range messageIDs { - _, err := backend.GetMessageSignatureByID(messageID) + for _, message := range messages { + _, err := backend.GetMessageSignature(message) require.ErrorContains(t, err, "failed to get warp message") } } @@ -94,8 +92,7 @@ func TestAddAndGetValidMessage(t *testing.T) { require.NoError(t, err) // Verify that a signature is returned successfully, and compare to expected signature. - messageID := testUnsignedMessage.ID() - signature, err := backend.GetMessageSignatureByID(messageID) + signature, err := backend.GetMessageSignature(testUnsignedMessage) require.NoError(t, err) expectedSig, err := warpSigner.Sign(testUnsignedMessage) @@ -113,8 +110,7 @@ func TestAddAndGetUnknownMessage(t *testing.T) { require.NoError(t, err) // Try getting a signature for a message that was not added. - messageID := testUnsignedMessage.ID() - _, err = backend.GetMessageSignatureByID(messageID) + _, err = backend.GetMessageSignature(testUnsignedMessage) require.Error(t, err) } @@ -162,8 +158,7 @@ func TestZeroSizedCache(t *testing.T) { require.NoError(t, err) // Verify that a signature is returned successfully, and compare to expected signature. - messageID := testUnsignedMessage.ID() - signature, err := backend.GetMessageSignatureByID(messageID) + signature, err := backend.GetMessageSignature(testUnsignedMessage) require.NoError(t, err) expectedSig, err := warpSigner.Sign(testUnsignedMessage) @@ -192,7 +187,7 @@ func TestOffChainMessages(t *testing.T) { require.NoError(err) require.Equal(testUnsignedMessage.Bytes(), msg.Bytes()) - signature, err := b.GetMessageSignatureByID(testUnsignedMessage.ID()) + signature, err := b.GetMessageSignature(testUnsignedMessage) require.NoError(err) expectedSignatureBytes, err := warpSigner.Sign(msg) require.NoError(err) diff --git a/warp/handlers/signature_request.go b/warp/handlers/signature_request.go index 25374de1ee..d37f301b31 100644 --- a/warp/handlers/signature_request.go +++ b/warp/handlers/signature_request.go @@ -45,7 +45,14 @@ func (s *SignatureRequestHandler) OnMessageSignatureRequest(ctx context.Context, s.stats.UpdateMessageSignatureRequestTime(time.Since(startTime)) }() - signature, err := s.backend.GetMessageSignatureByID(signatureRequest.MessageID) + unsignedMessage, err := s.backend.GetMessage(signatureRequest.MessageID) + if err != nil { + log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) + s.stats.IncMessageSignatureMiss() + return nil, nil + } + + signature, err := s.backend.GetMessageSignature(unsignedMessage) if err != nil { log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) s.stats.IncMessageSignatureMiss() diff --git a/warp/handlers/signature_request_p2p_test.go b/warp/handlers/signature_request_p2p_test.go index 677eb6e1f9..3104fe59b3 100644 --- a/warp/handlers/signature_request_p2p_test.go +++ b/warp/handlers/signature_request_p2p_test.go @@ -42,11 +42,10 @@ func TestMessageSignatureHandlerP2P(t *testing.T) { require.NoError(t, err) msg, err := avalancheWarp.NewUnsignedMessage(snowCtx.NetworkID, snowCtx.ChainID, offchainPayload.Bytes()) require.NoError(t, err) - messageID := msg.ID() require.NoError(t, backend.AddMessage(msg)) - signature, err := backend.GetMessageSignatureByID(messageID) + signature, err := backend.GetMessageSignature(msg) require.NoError(t, err) - offchainSignature, err := backend.GetMessageSignatureByID(offchainMessage.ID()) + offchainSignature, err := backend.GetMessageSignature(offchainMessage) require.NoError(t, err) unknownPayload, err := payload.NewAddressedCall([]byte{0, 0, 0}, []byte("unknown message")) diff --git a/warp/handlers/signature_request_test.go b/warp/handlers/signature_request_test.go index e723a50f86..1f699324cc 100644 --- a/warp/handlers/signature_request_test.go +++ b/warp/handlers/signature_request_test.go @@ -38,9 +38,9 @@ func TestMessageSignatureHandler(t *testing.T) { require.NoError(t, err) messageID := msg.ID() require.NoError(t, backend.AddMessage(msg)) - signature, err := backend.GetMessageSignatureByID(messageID) + signature, err := backend.GetMessageSignature(msg) require.NoError(t, err) - offchainSignature, err := backend.GetMessageSignatureByID(offchainMessage.ID()) + offchainSignature, err := backend.GetMessageSignature(offchainMessage) require.NoError(t, err) unknownMessageID := ids.GenerateTestID() diff --git a/warp/service.go b/warp/service.go index 64c0200c78..2bff8df77e 100644 --- a/warp/service.go +++ b/warp/service.go @@ -51,7 +51,11 @@ func (a *API) GetMessage(ctx context.Context, messageID ids.ID) (hexutil.Bytes, // GetMessageSignature returns the BLS signature associated with a messageID. func (a *API) GetMessageSignature(ctx context.Context, messageID ids.ID) (hexutil.Bytes, error) { - signature, err := a.backend.GetMessageSignatureByID(messageID) + unsignedMessage, err := a.backend.GetMessage(messageID) + if err != nil { + return nil, fmt.Errorf("failed to get message %s with error %w", messageID, err) + } + signature, err := a.backend.GetMessageSignature(unsignedMessage) if err != nil { return nil, fmt.Errorf("failed to get signature for message %s with error %w", messageID, err) } From c3638868d782847a23621bce534be1026b812af1 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Tue, 6 Aug 2024 16:43:53 -0700 Subject: [PATCH 05/23] assign to correct `err` --- warp/backend.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/warp/backend.go b/warp/backend.go index f8558b5195..2f919be257 100644 --- a/warp/backend.go +++ b/warp/backend.go @@ -167,7 +167,7 @@ func (b *backend) GetMessageSignature(unsignedMessage *avalancheWarp.UnsignedMes var err error for _, v := range append(b.messageValidators, b) { - err := v.ValidateMessage(unsignedMessage) + err = v.ValidateMessage(unsignedMessage) if err == nil { break } From 0bf1de65b2ebd21e9b74a0cc7332fe4dee04aeb6 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Tue, 6 Aug 2024 16:53:05 -0700 Subject: [PATCH 06/23] fix handler --- warp/handlers/signature_request.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/warp/handlers/signature_request.go b/warp/handlers/signature_request.go index d37f301b31..3a28cd994e 100644 --- a/warp/handlers/signature_request.go +++ b/warp/handlers/signature_request.go @@ -45,20 +45,20 @@ func (s *SignatureRequestHandler) OnMessageSignatureRequest(ctx context.Context, s.stats.UpdateMessageSignatureRequestTime(time.Since(startTime)) }() + var signature [bls.SignatureLen]byte unsignedMessage, err := s.backend.GetMessage(signatureRequest.MessageID) if err != nil { - log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) + log.Debug("Unknown warp message requested", "messageID", signatureRequest.MessageID) s.stats.IncMessageSignatureMiss() - return nil, nil - } - - signature, err := s.backend.GetMessageSignature(unsignedMessage) - if err != nil { - log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) - s.stats.IncMessageSignatureMiss() - signature = [bls.SignatureLen]byte{} } else { - s.stats.IncMessageSignatureHit() + signature, err = s.backend.GetMessageSignature(unsignedMessage) + if err != nil { + log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) + s.stats.IncMessageSignatureMiss() + signature = [bls.SignatureLen]byte{} + } else { + s.stats.IncMessageSignatureHit() + } } response := message.SignatureResponse{Signature: signature} From 8b3fb1cc89bfab9f1c341ddd84b06c661c259494 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Mon, 19 Aug 2024 14:22:11 -0700 Subject: [PATCH 07/23] move ValidatorUptime type to subnet-evm --- warp/handlers/validator_uptime_handler.go | 2 +- .../handlers/validator_uptime_handler_test.go | 2 +- warp/messages/codec.go | 33 ++++++++++++ warp/messages/payload.go | 39 ++++++++++++++ warp/messages/validator_uptime.go | 51 +++++++++++++++++++ 5 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 warp/messages/codec.go create mode 100644 warp/messages/payload.go create mode 100644 warp/messages/validator_uptime.go diff --git a/warp/handlers/validator_uptime_handler.go b/warp/handlers/validator_uptime_handler.go index 8f488b07fe..7b9e286304 100644 --- a/warp/handlers/validator_uptime_handler.go +++ b/warp/handlers/validator_uptime_handler.go @@ -8,8 +8,8 @@ import ( "fmt" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" - "github.com/ava-labs/avalanchego/vms/platformvm/warp/messages" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + "github.com/ava-labs/subnet-evm/warp/messages" "github.com/ethereum/go-ethereum/log" ) diff --git a/warp/handlers/validator_uptime_handler_test.go b/warp/handlers/validator_uptime_handler_test.go index d2a094c150..e0a009faad 100644 --- a/warp/handlers/validator_uptime_handler_test.go +++ b/warp/handlers/validator_uptime_handler_test.go @@ -8,8 +8,8 @@ import ( "github.com/ava-labs/avalanchego/ids" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" - "github.com/ava-labs/avalanchego/vms/platformvm/warp/messages" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + "github.com/ava-labs/subnet-evm/warp/messages" "github.com/stretchr/testify/require" ) diff --git a/warp/messages/codec.go b/warp/messages/codec.go new file mode 100644 index 0000000000..87d2fa334a --- /dev/null +++ b/warp/messages/codec.go @@ -0,0 +1,33 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package messages + +import ( + "errors" + + "github.com/ava-labs/avalanchego/codec" + "github.com/ava-labs/avalanchego/codec/linearcodec" + "github.com/ava-labs/avalanchego/utils/units" +) + +const ( + CodecVersion = 0 + + MaxMessageSize = 24 * units.KiB +) + +var Codec codec.Manager + +func init() { + Codec = codec.NewManager(MaxMessageSize) + lc := linearcodec.NewDefault() + + err := errors.Join( + lc.RegisterType(&ValidatorUptime{}), + Codec.RegisterCodec(CodecVersion, lc), + ) + if err != nil { + panic(err) + } +} diff --git a/warp/messages/payload.go b/warp/messages/payload.go new file mode 100644 index 0000000000..facf54524d --- /dev/null +++ b/warp/messages/payload.go @@ -0,0 +1,39 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package messages + +import ( + "errors" + "fmt" +) + +var errWrongType = errors.New("wrong payload type") + +// Payload provides a common interface for all payloads implemented by this +// package. +type Payload interface { + // Bytes returns the binary representation of this payload. + Bytes() []byte + + // initialize the payload with the provided binary representation. + initialize(b []byte) +} + +func Parse(bytes []byte) (Payload, error) { + var payload Payload + if _, err := Codec.Unmarshal(bytes, &payload); err != nil { + return nil, err + } + payload.initialize(bytes) + return payload, nil +} + +func initialize(p Payload) error { + bytes, err := Codec.Marshal(CodecVersion, &p) + if err != nil { + return fmt.Errorf("couldn't marshal %T payload: %w", p, err) + } + p.initialize(bytes) + return nil +} diff --git a/warp/messages/validator_uptime.go b/warp/messages/validator_uptime.go new file mode 100644 index 0000000000..3d3e4dd5dd --- /dev/null +++ b/warp/messages/validator_uptime.go @@ -0,0 +1,51 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package messages + +import ( + "fmt" + + "github.com/ava-labs/avalanchego/ids" +) + +// ValidatorUptime is signed when the ValidationID is known and the validator +// has been up for TotalUptime seconds. +type ValidatorUptime struct { + ValidationID ids.ID `serialize:"true"` + TotalUptime uint64 `serialize:"true"` + + bytes []byte +} + +// NewValidatorUptime creates a new *ValidatorUptime and initializes it. +func NewValidatorUptime(validationID ids.ID, totalUptime uint64) (*ValidatorUptime, error) { + bhp := &ValidatorUptime{ + ValidationID: validationID, + TotalUptime: totalUptime, + } + return bhp, initialize(bhp) +} + +// ParseValidatorUptime converts a slice of bytes into an initialized ValidatorUptime. +func ParseValidatorUptime(b []byte) (*ValidatorUptime, error) { + payloadIntf, err := Parse(b) + if err != nil { + return nil, err + } + payload, ok := payloadIntf.(*ValidatorUptime) + if !ok { + return nil, fmt.Errorf("%w: %T", errWrongType, payloadIntf) + } + return payload, nil +} + +// Bytes returns the binary representation of this payload. It assumes that the +// payload is initialized from either NewValidatorUptime or Parse. +func (b *ValidatorUptime) Bytes() []byte { + return b.bytes +} + +func (b *ValidatorUptime) initialize(bytes []byte) { + b.bytes = bytes +} From 008bc37f50d2df0ef2b31f1470069ce543bca8a9 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Mon, 19 Aug 2024 14:41:12 -0700 Subject: [PATCH 08/23] disable always signing --- plugin/evm/vm.go | 1 - warp/handlers/validator_uptime_handler.go | 38 ------------------- .../handlers/validator_uptime_handler_test.go | 35 ----------------- 3 files changed, 74 deletions(-) delete mode 100644 warp/handlers/validator_uptime_handler.go delete mode 100644 warp/handlers/validator_uptime_handler_test.go diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index dd3af26df8..2c6dfd55b9 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -497,7 +497,6 @@ func (vm *VM) Initialize( if err != nil { return err } - vm.warpBackend.AddMessageValidator(&handlers.ValidatorUptimeHandler{}) // clear warpdb on initialization if config enabled if vm.config.PruneWarpDB { diff --git a/warp/handlers/validator_uptime_handler.go b/warp/handlers/validator_uptime_handler.go deleted file mode 100644 index 7b9e286304..0000000000 --- a/warp/handlers/validator_uptime_handler.go +++ /dev/null @@ -1,38 +0,0 @@ -// (c) 2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package handlers - -import ( - "errors" - "fmt" - - avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" - "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" - "github.com/ava-labs/subnet-evm/warp/messages" - "github.com/ethereum/go-ethereum/log" -) - -var errInvalidRequest = errors.New("invalid request") - -type ValidatorUptimeHandler struct{} - -func (v *ValidatorUptimeHandler) ValidateMessage(unsignedMessage *avalancheWarp.UnsignedMessage) error { - parsed, err := payload.ParseAddressedCall(unsignedMessage.Payload) - if err != nil { - return fmt.Errorf("failed to parse payload: %w", err) - } - // TODO: Does nil/empty SourceAddress matter? - if len(parsed.SourceAddress) != 0 { - return errInvalidRequest - } - - vdr, err := messages.ParseValidatorUptime(parsed.Payload) - if err != nil { - return fmt.Errorf("failed to parse validator uptime message: %w", err) - } - - log.Info("Received validator uptime message", "validationID", vdr.ValidationID, "totalUptime", vdr.TotalUptime) - log.Warn("Signing validator uptime message by default, not production behavior", "validationID", vdr.ValidationID, "totalUptime", vdr.TotalUptime) - return nil -} diff --git a/warp/handlers/validator_uptime_handler_test.go b/warp/handlers/validator_uptime_handler_test.go deleted file mode 100644 index e0a009faad..0000000000 --- a/warp/handlers/validator_uptime_handler_test.go +++ /dev/null @@ -1,35 +0,0 @@ -// (c) 2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package handlers - -import ( - "testing" - - "github.com/ava-labs/avalanchego/ids" - avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" - "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" - "github.com/ava-labs/subnet-evm/warp/messages" - "github.com/stretchr/testify/require" -) - -func TestValidatorUptimeHandler(t *testing.T) { - require := require.New(t) - - v := &ValidatorUptimeHandler{} - - validationID := ids.GenerateTestID() - totalUptime := uint64(1_000_000) // arbitrary value - vdrUptime, err := messages.NewValidatorUptime(validationID, totalUptime) - require.NoError(err) - - addressedCall, err := payload.NewAddressedCall(nil, vdrUptime.Bytes()) - require.NoError(err) - - networkID := uint32(0) - sourceChain := ids.Empty - message, err := avalancheWarp.NewUnsignedMessage(networkID, sourceChain, addressedCall.Bytes()) - require.NoError(err) - - require.NoError(v.ValidateMessage(message)) -} From 48f0ab795ec44594a9518d79a0ae11a8c2f5922e Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Tue, 20 Aug 2024 10:34:29 -0700 Subject: [PATCH 09/23] implement on the type itself --- warp/backend.go | 38 +++++++++++++++++++++++++++----------- warp/messages/payload.go | 6 ++++++ 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/warp/backend.go b/warp/backend.go index 2f919be257..867f0e929f 100644 --- a/warp/backend.go +++ b/warp/backend.go @@ -15,6 +15,7 @@ import ( "github.com/ava-labs/avalanchego/utils/crypto/bls" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + "github.com/ava-labs/subnet-evm/warp/messages" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" ) @@ -165,14 +166,7 @@ func (b *backend) GetMessageSignature(unsignedMessage *avalancheWarp.UnsignedMes return sig, nil } - var err error - for _, v := range append(b.messageValidators, b) { - err = v.ValidateMessage(unsignedMessage) - if err == nil { - break - } - } - if err != nil { + if err := b.ValidateMessage(unsignedMessage); err != nil { return [bls.SignatureLen]byte{}, fmt.Errorf("failed to validate warp message: %w", err) } @@ -188,10 +182,32 @@ func (b *backend) GetMessageSignature(unsignedMessage *avalancheWarp.UnsignedMes } func (b *backend) ValidateMessage(unsignedMessage *avalancheWarp.UnsignedMessage) error { - messageID := unsignedMessage.ID() - _, err := b.GetMessage(messageID) + // Known on-chain messages should be signed + if _, err := b.GetMessage(unsignedMessage.ID()); err == nil { + return nil + } + + // Try to parse the payload as an AddressedCall + addressedCall, err := payload.ParseAddressedCall(unsignedMessage.Payload) if err != nil { - return fmt.Errorf("failed to get warp message %s from db: %w", messageID.String(), err) + return fmt.Errorf("failed to parse unknown message as AddressedCall: %w", err) + } + + // Further, parse the payload to see if it is a known type. + parsed, err := messages.Parse(addressedCall.Payload) + if err != nil { + return fmt.Errorf("failed to parse unknown message: %w", err) + } + + // Check if the message is a known type that can be signed on demand + signable, ok := parsed.(messages.Signable) + if !ok { + return fmt.Errorf("parsed message is not Signable: %T", signable) + } + + // Check if the message should be signed according to its type + if err := signable.VerifyMesssage(addressedCall.SourceAddress); err != nil { + return fmt.Errorf("failed to verify Signable message: %w", err) } return nil } diff --git a/warp/messages/payload.go b/warp/messages/payload.go index facf54524d..3776a1356d 100644 --- a/warp/messages/payload.go +++ b/warp/messages/payload.go @@ -20,6 +20,12 @@ type Payload interface { initialize(b []byte) } +// Signable is an optional interface that payloads can implement to allow +// on-the-fly signing of incoming messages by the warp backend. +type Signable interface { + VerifyMesssage(sourceAddress []byte) error +} + func Parse(bytes []byte) (Payload, error) { var payload Payload if _, err := Codec.Unmarshal(bytes, &payload); err != nil { From 991ff463cde8742b006e587f3667fd084abaefde Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Tue, 20 Aug 2024 10:57:24 -0700 Subject: [PATCH 10/23] remove unneeded code --- warp/backend.go | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/warp/backend.go b/warp/backend.go index 867f0e929f..360161a336 100644 --- a/warp/backend.go +++ b/warp/backend.go @@ -31,22 +31,12 @@ type BlockClient interface { GetAcceptedBlock(ctx context.Context, blockID ids.ID) (snowman.Block, error) } -type MessageValidator interface { - // If the validator returns nil, the message is considered valid and the - // backend will sign it. - ValidateMessage(*avalancheWarp.UnsignedMessage) error -} - // Backend tracks signature-eligible warp messages and provides an interface to fetch them. // The backend is also used to query for warp message signatures by the signature request handler. type Backend interface { // AddMessage signs [unsignedMessage] and adds it to the warp backend database AddMessage(unsignedMessage *avalancheWarp.UnsignedMessage) error - // AddMessageValidator adds a validator to the backend. The backend will sign - // messages that pass any of the validators, in addition to those known in the db. - AddMessageValidator(validator MessageValidator) - // GetMessageSignature returns the signature of the requested message. GetMessageSignature(message *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) @@ -73,7 +63,6 @@ type backend struct { blockSignatureCache *cache.LRU[ids.ID, [bls.SignatureLen]byte] messageCache *cache.LRU[ids.ID, *avalancheWarp.UnsignedMessage] offchainAddressedCallMsgs map[ids.ID]*avalancheWarp.UnsignedMessage - messageValidators []MessageValidator } // NewBackend creates a new Backend, and initializes the signature cache and message tracking database. @@ -100,10 +89,6 @@ func NewBackend( return b, b.initOffChainMessages(offchainMessages) } -func (b *backend) AddMessageValidator(validator MessageValidator) { - b.messageValidators = append(b.messageValidators, validator) -} - func (b *backend) initOffChainMessages(offchainMessages [][]byte) error { for i, offchainMsg := range offchainMessages { unsignedMsg, err := avalancheWarp.ParseUnsignedMessage(offchainMsg) From fe05d33d3b2d6ca036ff56dad7e3b920f7645233 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Tue, 20 Aug 2024 11:14:12 -0700 Subject: [PATCH 11/23] fix ut --- warp/backend_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/warp/backend_test.go b/warp/backend_test.go index 756e5f48a4..21013dfc24 100644 --- a/warp/backend_test.go +++ b/warp/backend_test.go @@ -74,7 +74,7 @@ func TestClearDB(t *testing.T) { // ensure all messages have been deleted for _, message := range messages { _, err := backend.GetMessageSignature(message) - require.ErrorContains(t, err, "failed to get warp message") + require.ErrorContains(t, err, "failed to validate warp message") } } From beea962863a745c5e66922ada5e12ecc1fd5a9e1 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Wed, 9 Oct 2024 16:46:10 +0300 Subject: [PATCH 12/23] implement acp118 signer and verifier --- go.mod | 2 +- go.sum | 4 +- plugin/evm/vm.go | 5 +- warp/backend.go | 110 ++++++++---- warp/handlers/signature_request_p2p.go | 151 ----------------- warp/handlers/signature_request_test.go | 2 - warp/handlers/signer_verifier_p2p.go | 156 ++++++++++++++++++ ...2p_test.go => signer_verifier_p2p_test.go} | 39 +++-- warp/handlers/stats.go | 44 ++--- 9 files changed, 292 insertions(+), 221 deletions(-) delete mode 100644 warp/handlers/signature_request_p2p.go create mode 100644 warp/handlers/signer_verifier_p2p.go rename warp/handlers/{signature_request_p2p_test.go => signer_verifier_p2p_test.go} (82%) diff --git a/go.mod b/go.mod index f15a30e537..08265830d2 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22.8 require ( github.com/VictoriaMetrics/fastcache v1.12.1 github.com/antithesishq/antithesis-sdk-go v0.3.8 - github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241003220930-43d5b435a644 + github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241004185122-5285749cc752 github.com/cespare/cp v0.1.0 github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 github.com/davecgh/go-spew v1.1.1 diff --git a/go.sum b/go.sum index 089fdbe3f5..1693074e83 100644 --- a/go.sum +++ b/go.sum @@ -58,8 +58,8 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax github.com/antithesishq/antithesis-sdk-go v0.3.8 h1:OvGoHxIcOXFJLyn9IJQ5DzByZ3YVAWNBc394ObzDRb8= github.com/antithesishq/antithesis-sdk-go v0.3.8/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241003220930-43d5b435a644 h1:F3SVwl0bmatEgtL7FeREoLOPGZkNCID6gQk94WmeCgY= -github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241003220930-43d5b435a644/go.mod h1:qSHmog3wMVjo/ruIAQo0ppXAilyni07NIu5K88RyhWE= +github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241004185122-5285749cc752 h1:pQh5HA1sf31baNmN6RZpI02JOLmv7o7TcBY4VpuOSMI= +github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241004185122-5285749cc752/go.mod h1:qSHmog3wMVjo/ruIAQo0ppXAilyni07NIu5K88RyhWE= github.com/ava-labs/coreth v0.13.8 h1:f14X3KgwHl9LwzfxlN6S4bbn5VA2rhEsNnHaRLSTo/8= github.com/ava-labs/coreth v0.13.8/go.mod h1:t3BSv/eQv0AlDPMfEDCMMoD/jq1RkUsbFzQAFg5qBcE= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 376a8a12c7..b874b6e53d 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -70,6 +70,7 @@ import ( "github.com/ava-labs/avalanchego/database/prefixdb" "github.com/ava-labs/avalanchego/database/versiondb" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/network/p2p/acp118" "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/snow/consensus/snowman" "github.com/ava-labs/avalanchego/snow/engine/snowman/block" @@ -624,7 +625,9 @@ func (vm *VM) initializeHandlers() { }) // Add p2p warp message warpHandler - warpHandler := handlers.NewSignatureRequestHandlerP2P(vm.warpBackend, vm.networkCodec) + signerVerifier := handlers.NewSignerVerifier(vm.warpBackend, vm.networkCodec) + // TODO: consider chancing acp118 handler to take a single Signer interface + warpHandler := acp118.NewHandler(signerVerifier, signerVerifier) vm.Network.AddHandler(p2p.SignatureRequestHandlerID, warpHandler) vm.setAppRequestHandlers() diff --git a/warp/backend.go b/warp/backend.go index 360161a336..b67be9ac70 100644 --- a/warp/backend.go +++ b/warp/backend.go @@ -37,10 +37,10 @@ type Backend interface { // AddMessage signs [unsignedMessage] and adds it to the warp backend database AddMessage(unsignedMessage *avalancheWarp.UnsignedMessage) error - // GetMessageSignature returns the signature of the requested message. + // GetMessageSignature validates the message and returns the signature of the requested message. GetMessageSignature(message *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) - // GetBlockSignature returns the signature of the requested message hash. + // GetBlockSignature validates blockID and returns the signature of the requested message hash. GetBlockSignature(blockID ids.ID) ([bls.SignatureLen]byte, error) // GetMessage retrieves the [unsignedMessage] from the warp backend database if available @@ -48,6 +48,18 @@ type Backend interface { // to unsignedMessage (and this method can be removed). GetMessage(messageHash ids.ID) (*avalancheWarp.UnsignedMessage, error) + // ValidateMessage validates the [unsignedMessage] and returns an error if the message is invalid. + ValidateMessage(unsignedMessage *avalancheWarp.UnsignedMessage) error + + // ValidateBlockMessage validates the block message with the given [blockID] and returns an error if the message is invalid. + ValidateBlockMessage(blockID ids.ID) error + + // SignMessage signs the [unsignedMessage] and returns the signature. + SignMessage(unsignedMessage *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) + + // SignBlock signs the block message with the given [blockID] and returns the signature. + SignBlock(blockID ids.ID) ([bls.SignatureLen]byte, error) + // Clear clears the entire db Clear() error } @@ -154,21 +166,27 @@ func (b *backend) GetMessageSignature(unsignedMessage *avalancheWarp.UnsignedMes if err := b.ValidateMessage(unsignedMessage); err != nil { return [bls.SignatureLen]byte{}, fmt.Errorf("failed to validate warp message: %w", err) } + return b.signMessage(unsignedMessage) +} - var signature [bls.SignatureLen]byte - sig, err := b.warpSigner.Sign(unsignedMessage) - if err != nil { - return [bls.SignatureLen]byte{}, fmt.Errorf("failed to sign warp message: %w", err) +func (b *backend) SignMessage(unsignedMessage *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) { + messageID := unsignedMessage.ID() + + if sig, ok := b.messageSignatureCache.Get(messageID); ok { + return sig, nil } - copy(signature[:], sig) - b.messageSignatureCache.Put(messageID, signature) - return signature, nil + return b.signMessage(unsignedMessage) } func (b *backend) ValidateMessage(unsignedMessage *avalancheWarp.UnsignedMessage) error { + messageID := unsignedMessage.ID() + + if _, ok := b.messageSignatureCache.Get(messageID); ok { + return nil + } // Known on-chain messages should be signed - if _, err := b.GetMessage(unsignedMessage.ID()); err == nil { + if _, err := b.GetMessage(messageID); err == nil { return nil } @@ -197,34 +215,38 @@ func (b *backend) ValidateMessage(unsignedMessage *avalancheWarp.UnsignedMessage return nil } -func (b *backend) GetBlockSignature(blockID ids.ID) ([bls.SignatureLen]byte, error) { - log.Debug("Getting block from backend", "blockID", blockID) - if sig, ok := b.blockSignatureCache.Get(blockID); ok { - return sig, nil +func (b *backend) ValidateBlockMessage(blockID ids.ID) error { + if _, ok := b.blockSignatureCache.Get(blockID); ok { + return nil } _, err := b.blockClient.GetAcceptedBlock(context.TODO(), blockID) if err != nil { - return [bls.SignatureLen]byte{}, fmt.Errorf("failed to get block %s: %w", blockID, err) + return fmt.Errorf("failed to get block %s: %w", blockID, err) } - var signature [bls.SignatureLen]byte - blockHashPayload, err := payload.NewHash(blockID) - if err != nil { - return [bls.SignatureLen]byte{}, fmt.Errorf("failed to create new block hash payload: %w", err) + return nil +} + +func (b *backend) GetBlockSignature(blockID ids.ID) ([bls.SignatureLen]byte, error) { + log.Debug("Getting block from backend", "blockID", blockID) + if sig, ok := b.blockSignatureCache.Get(blockID); ok { + return sig, nil } - unsignedMessage, err := avalancheWarp.NewUnsignedMessage(b.networkID, b.sourceChainID, blockHashPayload.Bytes()) - if err != nil { - return [bls.SignatureLen]byte{}, fmt.Errorf("failed to create new unsigned warp message: %w", err) + + if err := b.ValidateBlockMessage(blockID); err != nil { + return [bls.SignatureLen]byte{}, fmt.Errorf("failed to validate block message: %w", err) } - sig, err := b.warpSigner.Sign(unsignedMessage) - if err != nil { - return [bls.SignatureLen]byte{}, fmt.Errorf("failed to sign warp message: %w", err) + + return b.signBlock(blockID) +} + +func (b *backend) SignBlock(blockID ids.ID) ([bls.SignatureLen]byte, error) { + if sig, ok := b.blockSignatureCache.Get(blockID); ok { + return sig, nil } - copy(signature[:], sig) - b.blockSignatureCache.Put(blockID, signature) - return signature, nil + return b.signBlock(blockID) } func (b *backend) GetMessage(messageID ids.ID) (*avalancheWarp.UnsignedMessage, error) { @@ -248,3 +270,35 @@ func (b *backend) GetMessage(messageID ids.ID) (*avalancheWarp.UnsignedMessage, return unsignedMessage, nil } + +func (b *backend) signMessage(unsignedMessage *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) { + sig, err := b.warpSigner.Sign(unsignedMessage) + if err != nil { + return [bls.SignatureLen]byte{}, fmt.Errorf("failed to sign warp message: %w", err) + } + + var signature [bls.SignatureLen]byte + copy(signature[:], sig) + b.messageSignatureCache.Put(unsignedMessage.ID(), signature) + return signature, nil +} + +func (b *backend) signBlock(blockID ids.ID) ([bls.SignatureLen]byte, error) { + blockHashPayload, err := payload.NewHash(blockID) + if err != nil { + return [bls.SignatureLen]byte{}, fmt.Errorf("failed to create new block hash payload: %w", err) + } + unsignedMessage, err := avalancheWarp.NewUnsignedMessage(b.networkID, b.sourceChainID, blockHashPayload.Bytes()) + if err != nil { + return [bls.SignatureLen]byte{}, fmt.Errorf("failed to create new unsigned warp message: %w", err) + } + sig, err := b.warpSigner.Sign(unsignedMessage) + if err != nil { + return [bls.SignatureLen]byte{}, fmt.Errorf("failed to sign warp message: %w", err) + } + + var signature [bls.SignatureLen]byte + copy(signature[:], sig) + b.blockSignatureCache.Put(blockID, signature) + return signature, nil +} diff --git a/warp/handlers/signature_request_p2p.go b/warp/handlers/signature_request_p2p.go deleted file mode 100644 index cb711974b2..0000000000 --- a/warp/handlers/signature_request_p2p.go +++ /dev/null @@ -1,151 +0,0 @@ -// (c) 2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package handlers - -import ( - "context" - "fmt" - "time" - - "github.com/ava-labs/avalanchego/codec" - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/network/p2p" - "github.com/ava-labs/avalanchego/proto/pb/sdk" - "github.com/ava-labs/avalanchego/snow/engine/common" - "github.com/ava-labs/avalanchego/utils/crypto/bls" - avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" - "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" - "github.com/ava-labs/subnet-evm/warp" - "google.golang.org/protobuf/proto" -) - -var _ p2p.Handler = (*SignatureRequestHandlerP2P)(nil) - -const ( - ErrFailedToParse = iota - ErrFailedToGetSig - ErrFailedToMarshal -) - -type AddressedCallHandler interface { - GetMessageSignature(*avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) -} - -// SignatureRequestHandlerP2P serves warp signature requests using the p2p -// framework from avalanchego. It is a peer.RequestHandler for -// message.MessageSignatureRequest. -type SignatureRequestHandlerP2P struct { - backend warp.Backend - codec codec.Manager - stats *handlerStats -} - -func NewSignatureRequestHandlerP2P(backend warp.Backend, codec codec.Manager) *SignatureRequestHandlerP2P { - return &SignatureRequestHandlerP2P{ - backend: backend, - codec: codec, - stats: newStats(), - } -} - -func (s *SignatureRequestHandlerP2P) AppRequest( - ctx context.Context, - nodeID ids.NodeID, - deadline time.Time, - requestBytes []byte, -) ([]byte, *common.AppError) { - // Per ACP-118, the requestBytes are the serialized form of - // sdk.SignatureRequest. - req := new(sdk.SignatureRequest) - if err := proto.Unmarshal(requestBytes, req); err != nil { - return nil, &common.AppError{ - Code: ErrFailedToParse, - Message: "failed to unmarshal request: " + err.Error(), - } - } - - unsignedMessage, err := avalancheWarp.ParseUnsignedMessage(req.Message) - if err != nil { - return nil, &common.AppError{ - Code: ErrFailedToParse, - Message: "failed to parse unsigned message: " + err.Error(), - } - } - parsed, err := payload.Parse(unsignedMessage.Payload) - if err != nil { - return nil, &common.AppError{ - Code: ErrFailedToParse, - Message: "failed to parse payload: " + err.Error(), - } - } - - var sig [bls.SignatureLen]byte - switch p := parsed.(type) { - case *payload.AddressedCall: - sig, err = s.GetMessageSignature(unsignedMessage) - if err != nil { - s.stats.IncMessageSignatureMiss() - } else { - s.stats.IncMessageSignatureHit() - } - case *payload.Hash: - sig, err = s.GetBlockSignature(p.Hash) - if err != nil { - s.stats.IncBlockSignatureMiss() - } else { - s.stats.IncBlockSignatureHit() - } - default: - return nil, &common.AppError{ - Code: ErrFailedToParse, - Message: fmt.Sprintf("unknown payload type: %T", p), - } - } - if err != nil { - return nil, &common.AppError{ - Code: ErrFailedToGetSig, - Message: "failed to get signature: " + err.Error(), - } - } - - // Per ACP-118, the responseBytes are the serialized form of - // sdk.SignatureResponse. - resp := &sdk.SignatureResponse{Signature: sig[:]} - respBytes, err := proto.Marshal(resp) - if err != nil { - return nil, &common.AppError{ - Code: ErrFailedToMarshal, - Message: "failed to marshal response: " + err.Error(), - } - } - return respBytes, nil -} - -func (s *SignatureRequestHandlerP2P) GetMessageSignature(message *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) { - startTime := time.Now() - s.stats.IncMessageSignatureRequest() - - // Always report signature request time - defer func() { - s.stats.UpdateMessageSignatureRequestTime(time.Since(startTime)) - }() - - return s.backend.GetMessageSignature(message) -} - -func (s *SignatureRequestHandlerP2P) GetBlockSignature(blockID ids.ID) ([bls.SignatureLen]byte, error) { - startTime := time.Now() - s.stats.IncBlockSignatureRequest() - - // Always report signature request time - defer func() { - s.stats.UpdateBlockSignatureRequestTime(time.Since(startTime)) - }() - - return s.backend.GetBlockSignature(blockID) -} - -func (s *SignatureRequestHandlerP2P) AppGossip( - ctx context.Context, nodeID ids.NodeID, gossipBytes []byte) { -} diff --git a/warp/handlers/signature_request_test.go b/warp/handlers/signature_request_test.go index 1f699324cc..455ac268e2 100644 --- a/warp/handlers/signature_request_test.go +++ b/warp/handlers/signature_request_test.go @@ -101,7 +101,6 @@ func TestMessageSignatureHandler(t *testing.T) { for name, test := range tests { t.Run(name, func(t *testing.T) { handler := NewSignatureRequestHandler(backend, message.Codec) - handler.stats.Clear() request, expectedResponse := test.setup() responseBytes, err := handler.OnMessageSignatureRequest(context.Background(), ids.GenerateTestNodeID(), 1, request) @@ -188,7 +187,6 @@ func TestBlockSignatureHandler(t *testing.T) { for name, test := range tests { t.Run(name, func(t *testing.T) { handler := NewSignatureRequestHandler(backend, message.Codec) - handler.stats.Clear() request, expectedResponse := test.setup() responseBytes, err := handler.OnBlockSignatureRequest(context.Background(), ids.GenerateTestNodeID(), 1, request) diff --git a/warp/handlers/signer_verifier_p2p.go b/warp/handlers/signer_verifier_p2p.go new file mode 100644 index 0000000000..db24fe9561 --- /dev/null +++ b/warp/handlers/signer_verifier_p2p.go @@ -0,0 +1,156 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package handlers + +import ( + "context" + "fmt" + "time" + + "github.com/ava-labs/avalanchego/codec" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/network/p2p/acp118" + "github.com/ava-labs/avalanchego/snow/engine/common" + avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" + "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + "github.com/ava-labs/subnet-evm/warp" +) + +var ( + _ avalancheWarp.Signer = (*p2pSignerVerifier)(nil) + _ acp118.Verifier = (*p2pSignerVerifier)(nil) +) + +const ( + ParseErrCode = iota + GetSigErrCode + MarshalErrCode + ValidateErrCode +) + +var ( + errUnknownPayloadType = fmt.Errorf("unknown payload type") + errFailedToParse = fmt.Errorf("failed to parse payload") + errFailedToGetSig = fmt.Errorf("failed to get signature") +) + +type SignerVerifier interface { + acp118.Verifier + avalancheWarp.Signer +} + +// p2pSignerVerifier serves warp signature requests using the p2p +// framework from avalanchego. It is a peer.RequestHandler for +// message.MessageSignatureRequest. +type p2pSignerVerifier struct { + backend warp.Backend + codec codec.Manager + stats *handlerStats +} + +func NewSignerVerifier(backend warp.Backend, codec codec.Manager) SignerVerifier { + return &p2pSignerVerifier{ + backend: backend, + codec: codec, + stats: newStats(), + } +} + +func (s *p2pSignerVerifier) Verify(_ context.Context, unsignedMessage *avalancheWarp.UnsignedMessage, _ []byte) *common.AppError { + parsed, err := payload.Parse(unsignedMessage.Payload) + if err != nil { + return &common.AppError{ + Code: ParseErrCode, + Message: "failed to parse payload: " + err.Error(), + } + } + + switch p := parsed.(type) { + case *payload.AddressedCall: + err = s.backend.ValidateMessage(unsignedMessage) + if err != nil { + s.stats.IncMessageSignatureValidationFail() + return &common.AppError{ + Code: ValidateErrCode, + Message: "failed to validate message: " + err.Error(), + } + } + case *payload.Hash: + err = s.backend.ValidateBlockMessage(p.Hash) + if err != nil { + s.stats.IncBlockSignatureValidationFail() + return &common.AppError{ + Code: ValidateErrCode, + Message: "failed to validate block message: " + err.Error(), + } + } + default: + return &common.AppError{ + Code: ParseErrCode, + Message: fmt.Sprintf("unknown payload type: %T", p), + } + } + return nil +} + +func (s *p2pSignerVerifier) Sign(unsignedMessage *avalancheWarp.UnsignedMessage) ([]byte, error) { + parsed, err := payload.Parse(unsignedMessage.Payload) + if err != nil { + return nil, fmt.Errorf("%w: %s", errFailedToParse, err.Error()) + } + + var sig []byte + switch p := parsed.(type) { + case *payload.AddressedCall: + sig, err = s.GetMessageSignature(unsignedMessage) + if err != nil { + s.stats.IncMessageSignatureMiss() + } else { + s.stats.IncMessageSignatureHit() + } + case *payload.Hash: + sig, err = s.GetBlockSignature(p.Hash) + if err != nil { + s.stats.IncBlockSignatureMiss() + } else { + s.stats.IncBlockSignatureHit() + } + default: + return nil, fmt.Errorf("%w: %T", errUnknownPayloadType, p) + } + + if err != nil { + return nil, fmt.Errorf("%w: %s", errFailedToGetSig, err.Error()) + } + + return sig, nil +} + +func (s *p2pSignerVerifier) GetMessageSignature(message *avalancheWarp.UnsignedMessage) ([]byte, error) { + startTime := time.Now() + s.stats.IncMessageSignatureRequest() + + // Always report signature request time + defer func() { + s.stats.UpdateMessageSignatureRequestTime(time.Since(startTime)) + }() + + // TODO: consider changing backend to return []byte + sig, err := s.backend.GetMessageSignature(message) + return sig[:], err +} + +func (s *p2pSignerVerifier) GetBlockSignature(blockID ids.ID) ([]byte, error) { + startTime := time.Now() + s.stats.IncBlockSignatureRequest() + + // Always report signature request time + defer func() { + s.stats.UpdateBlockSignatureRequestTime(time.Since(startTime)) + }() + + // TODO: consider changing backend to return []byte + sig, err := s.backend.GetBlockSignature(blockID) + return sig[:], err +} diff --git a/warp/handlers/signature_request_p2p_test.go b/warp/handlers/signer_verifier_p2p_test.go similarity index 82% rename from warp/handlers/signature_request_p2p_test.go rename to warp/handlers/signer_verifier_p2p_test.go index 3104fe59b3..76eba68317 100644 --- a/warp/handlers/signature_request_p2p_test.go +++ b/warp/handlers/signer_verifier_p2p_test.go @@ -10,6 +10,7 @@ import ( "github.com/ava-labs/avalanchego/database/memdb" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/network/p2p/acp118" "github.com/ava-labs/avalanchego/proto/pb/sdk" "github.com/ava-labs/avalanchego/snow/engine/common" "github.com/ava-labs/avalanchego/utils/crypto/bls" @@ -23,7 +24,7 @@ import ( "google.golang.org/protobuf/proto" ) -func TestMessageSignatureHandlerP2P(t *testing.T) { +func TestMessageSignatures(t *testing.T) { database := memdb.New() snowCtx := utils.TestSnowContext() blsSecretKey, err := bls.NewSecretKey() @@ -64,9 +65,11 @@ func TestMessageSignatureHandlerP2P(t *testing.T) { }, verifyStats: func(t *testing.T, stats *handlerStats) { require.EqualValues(t, 1, stats.messageSignatureRequest.Snapshot().Count()) + require.EqualValues(t, 0, stats.messageSignatureValidationFail.Snapshot().Count()) require.EqualValues(t, 1, stats.messageSignatureHit.Snapshot().Count()) require.EqualValues(t, 0, stats.messageSignatureMiss.Snapshot().Count()) require.EqualValues(t, 0, stats.blockSignatureRequest.Snapshot().Count()) + require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) require.EqualValues(t, 0, stats.blockSignatureHit.Snapshot().Count()) require.EqualValues(t, 0, stats.blockSignatureMiss.Snapshot().Count()) }, @@ -77,9 +80,11 @@ func TestMessageSignatureHandlerP2P(t *testing.T) { }, verifyStats: func(t *testing.T, stats *handlerStats) { require.EqualValues(t, 1, stats.messageSignatureRequest.Snapshot().Count()) + require.EqualValues(t, 0, stats.messageSignatureValidationFail.Snapshot().Count()) require.EqualValues(t, 1, stats.messageSignatureHit.Snapshot().Count()) require.EqualValues(t, 0, stats.messageSignatureMiss.Snapshot().Count()) require.EqualValues(t, 0, stats.blockSignatureRequest.Snapshot().Count()) + require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) require.EqualValues(t, 0, stats.blockSignatureHit.Snapshot().Count()) require.EqualValues(t, 0, stats.blockSignatureMiss.Snapshot().Count()) }, @@ -89,21 +94,23 @@ func TestMessageSignatureHandlerP2P(t *testing.T) { return sdk.SignatureRequest{Message: unknownMessage.Bytes()}, nil }, verifyStats: func(t *testing.T, stats *handlerStats) { - require.EqualValues(t, 1, stats.messageSignatureRequest.Snapshot().Count()) + require.EqualValues(t, 0, stats.messageSignatureRequest.Snapshot().Count()) + require.EqualValues(t, 1, stats.messageSignatureValidationFail.Snapshot().Count()) require.EqualValues(t, 0, stats.messageSignatureHit.Snapshot().Count()) - require.EqualValues(t, 1, stats.messageSignatureMiss.Snapshot().Count()) + require.EqualValues(t, 0, stats.messageSignatureMiss.Snapshot().Count()) require.EqualValues(t, 0, stats.blockSignatureRequest.Snapshot().Count()) + require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) require.EqualValues(t, 0, stats.blockSignatureHit.Snapshot().Count()) require.EqualValues(t, 0, stats.blockSignatureMiss.Snapshot().Count()) }, - err: &common.AppError{Code: ErrFailedToGetSig}, + err: &common.AppError{Code: ValidateErrCode}, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { - handler := NewSignatureRequestHandlerP2P(backend, message.Codec) - handler.stats.Clear() + signerVerifier := NewSignerVerifier(backend, message.Codec) + handler := acp118.NewHandler(signerVerifier, signerVerifier) request, expectedResponse := test.setup() requestBytes, err := proto.Marshal(&request) @@ -115,7 +122,7 @@ func TestMessageSignatureHandlerP2P(t *testing.T) { require.Nil(t, appErr) } - test.verifyStats(t, handler.stats) + test.verifyStats(t, signerVerifier.(*p2pSignerVerifier).stats) // If the expected response is empty, assert that the handler returns an empty response and return early. if len(expectedResponse) == 0 { @@ -131,7 +138,7 @@ func TestMessageSignatureHandlerP2P(t *testing.T) { } } -func TestBlockSignatureHandlerP2P(t *testing.T) { +func TestBlockSignatures(t *testing.T) { database := memdb.New() snowCtx := utils.TestSnowContext() blsSecretKey, err := bls.NewSecretKey() @@ -176,9 +183,11 @@ func TestBlockSignatureHandlerP2P(t *testing.T) { }, verifyStats: func(t *testing.T, stats *handlerStats) { require.EqualValues(t, 0, stats.messageSignatureRequest.Snapshot().Count()) + require.EqualValues(t, 0, stats.messageSignatureValidationFail.Snapshot().Count()) require.EqualValues(t, 0, stats.messageSignatureHit.Snapshot().Count()) require.EqualValues(t, 0, stats.messageSignatureMiss.Snapshot().Count()) require.EqualValues(t, 1, stats.blockSignatureRequest.Snapshot().Count()) + require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) require.EqualValues(t, 1, stats.blockSignatureHit.Snapshot().Count()) require.EqualValues(t, 0, stats.blockSignatureMiss.Snapshot().Count()) }, @@ -189,20 +198,22 @@ func TestBlockSignatureHandlerP2P(t *testing.T) { }, verifyStats: func(t *testing.T, stats *handlerStats) { require.EqualValues(t, 0, stats.messageSignatureRequest.Snapshot().Count()) + require.EqualValues(t, 0, stats.messageSignatureValidationFail.Snapshot().Count()) require.EqualValues(t, 0, stats.messageSignatureHit.Snapshot().Count()) require.EqualValues(t, 0, stats.messageSignatureMiss.Snapshot().Count()) - require.EqualValues(t, 1, stats.blockSignatureRequest.Snapshot().Count()) + require.EqualValues(t, 0, stats.blockSignatureRequest.Snapshot().Count()) + require.EqualValues(t, 1, stats.blockSignatureValidationFail.Snapshot().Count()) require.EqualValues(t, 0, stats.blockSignatureHit.Snapshot().Count()) - require.EqualValues(t, 1, stats.blockSignatureMiss.Snapshot().Count()) + require.EqualValues(t, 0, stats.blockSignatureMiss.Snapshot().Count()) }, - err: &common.AppError{Code: ErrFailedToGetSig}, + err: &common.AppError{Code: ValidateErrCode}, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { - handler := NewSignatureRequestHandlerP2P(backend, message.Codec) - handler.stats.Clear() + signerVerifier := NewSignerVerifier(backend, message.Codec) + handler := acp118.NewHandler(signerVerifier, signerVerifier) request, expectedResponse := test.setup() requestBytes, err := proto.Marshal(&request) @@ -214,7 +225,7 @@ func TestBlockSignatureHandlerP2P(t *testing.T) { require.Nil(t, appErr) } - test.verifyStats(t, handler.stats) + test.verifyStats(t, signerVerifier.(*p2pSignerVerifier).stats) // If the expected response is empty, assert that the handler returns an empty response and return early. if len(expectedResponse) == 0 { diff --git a/warp/handlers/stats.go b/warp/handlers/stats.go index 481f2aaac0..545013fcd3 100644 --- a/warp/handlers/stats.go +++ b/warp/handlers/stats.go @@ -12,11 +12,13 @@ import ( type handlerStats struct { // MessageSignatureRequestHandler metrics messageSignatureRequest metrics.Counter + messageSignatureValidationFail metrics.Counter messageSignatureHit metrics.Counter messageSignatureMiss metrics.Counter messageSignatureRequestDuration metrics.Gauge // BlockSignatureRequestHandler metrics blockSignatureRequest metrics.Counter + blockSignatureValidationFail metrics.Counter blockSignatureHit metrics.Counter blockSignatureMiss metrics.Counter blockSignatureRequestDuration metrics.Gauge @@ -24,36 +26,34 @@ type handlerStats struct { func newStats() *handlerStats { return &handlerStats{ - messageSignatureRequest: metrics.GetOrRegisterCounter("message_signature_request_count", nil), - messageSignatureHit: metrics.GetOrRegisterCounter("message_signature_request_hit", nil), - messageSignatureMiss: metrics.GetOrRegisterCounter("message_signature_request_miss", nil), - messageSignatureRequestDuration: metrics.GetOrRegisterGauge("message_signature_request_duration", nil), - blockSignatureRequest: metrics.GetOrRegisterCounter("block_signature_request_count", nil), - blockSignatureHit: metrics.GetOrRegisterCounter("block_signature_request_hit", nil), - blockSignatureMiss: metrics.GetOrRegisterCounter("block_signature_request_miss", nil), - blockSignatureRequestDuration: metrics.GetOrRegisterGauge("block_signature_request_duration", nil), + messageSignatureRequest: metrics.NewRegisteredCounter("message_signature_request_count", nil), + messageSignatureValidationFail: metrics.NewRegisteredCounter("message_signature_request_validation_fail", nil), + messageSignatureHit: metrics.NewRegisteredCounter("message_signature_request_hit", nil), + messageSignatureMiss: metrics.NewRegisteredCounter("message_signature_request_miss", nil), + messageSignatureRequestDuration: metrics.NewRegisteredGauge("message_signature_request_duration", nil), + blockSignatureRequest: metrics.NewRegisteredCounter("block_signature_request_count", nil), + blockSignatureValidationFail: metrics.NewRegisteredCounter("block_signature_request_validation_fail", nil), + blockSignatureHit: metrics.NewRegisteredCounter("block_signature_request_hit", nil), + blockSignatureMiss: metrics.NewRegisteredCounter("block_signature_request_miss", nil), + blockSignatureRequestDuration: metrics.NewRegisteredGauge("block_signature_request_duration", nil), } } func (h *handlerStats) IncMessageSignatureRequest() { h.messageSignatureRequest.Inc(1) } -func (h *handlerStats) IncMessageSignatureHit() { h.messageSignatureHit.Inc(1) } -func (h *handlerStats) IncMessageSignatureMiss() { h.messageSignatureMiss.Inc(1) } +func (h *handlerStats) IncMessageSignatureValidationFail() { + h.messageSignatureValidationFail.Inc(1) +} +func (h *handlerStats) IncMessageSignatureHit() { h.messageSignatureHit.Inc(1) } +func (h *handlerStats) IncMessageSignatureMiss() { h.messageSignatureMiss.Inc(1) } func (h *handlerStats) UpdateMessageSignatureRequestTime(duration time.Duration) { h.messageSignatureRequestDuration.Inc(int64(duration)) } func (h *handlerStats) IncBlockSignatureRequest() { h.blockSignatureRequest.Inc(1) } -func (h *handlerStats) IncBlockSignatureHit() { h.blockSignatureHit.Inc(1) } -func (h *handlerStats) IncBlockSignatureMiss() { h.blockSignatureMiss.Inc(1) } +func (h *handlerStats) IncBlockSignatureValidationFail() { + h.blockSignatureValidationFail.Inc(1) +} +func (h *handlerStats) IncBlockSignatureHit() { h.blockSignatureHit.Inc(1) } +func (h *handlerStats) IncBlockSignatureMiss() { h.blockSignatureMiss.Inc(1) } func (h *handlerStats) UpdateBlockSignatureRequestTime(duration time.Duration) { h.blockSignatureRequestDuration.Inc(int64(duration)) } -func (h *handlerStats) Clear() { - h.messageSignatureRequest.Clear() - h.messageSignatureHit.Clear() - h.messageSignatureMiss.Clear() - h.messageSignatureRequestDuration.Update(0) - h.blockSignatureRequest.Clear() - h.blockSignatureHit.Clear() - h.blockSignatureMiss.Clear() - h.blockSignatureRequestDuration.Update(0) -} From 701e2ec5e28da9e78d2a103a6fa2b343568ba4a1 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Wed, 9 Oct 2024 17:33:23 +0300 Subject: [PATCH 13/23] avoid revalidating in sign --- warp/handlers/signer_verifier_p2p.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/warp/handlers/signer_verifier_p2p.go b/warp/handlers/signer_verifier_p2p.go index db24fe9561..6237217ee2 100644 --- a/warp/handlers/signer_verifier_p2p.go +++ b/warp/handlers/signer_verifier_p2p.go @@ -137,7 +137,7 @@ func (s *p2pSignerVerifier) GetMessageSignature(message *avalancheWarp.UnsignedM }() // TODO: consider changing backend to return []byte - sig, err := s.backend.GetMessageSignature(message) + sig, err := s.backend.SignMessage(message) return sig[:], err } @@ -151,6 +151,6 @@ func (s *p2pSignerVerifier) GetBlockSignature(blockID ids.ID) ([]byte, error) { }() // TODO: consider changing backend to return []byte - sig, err := s.backend.GetBlockSignature(blockID) + sig, err := s.backend.SignBlock(blockID) return sig[:], err } From 1c98afaedb3cfbd4e4ea3dfe7d21a10cdc241fcc Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Sun, 13 Oct 2024 12:52:39 +0300 Subject: [PATCH 14/23] refactor warp backend to use acp118 handler --- go.mod | 2 +- go.sum | 4 + plugin/evm/vm.go | 42 ++-- plugin/evm/vm_warp_test.go | 8 +- warp/backend.go | 180 ++++------------ warp/backend_test.go | 59 +----- warp/handlers/signature_request.go | 9 +- warp/handlers/signature_request_test.go | 7 +- warp/handlers/signer_verifier_p2p.go | 156 -------------- warp/handlers/signer_verifier_p2p_test.go | 242 ---------------------- warp/handlers/stats.go | 18 +- warp/messages/payload.go | 6 - warp/stats.go | 36 ++++ warp/verifier_backend.go | 105 ++++++++++ warp/verifier_backend_test.go | 222 ++++++++++++++++++++ warp/wrapped_cache.go | 52 +++++ 16 files changed, 515 insertions(+), 633 deletions(-) delete mode 100644 warp/handlers/signer_verifier_p2p.go delete mode 100644 warp/handlers/signer_verifier_p2p_test.go create mode 100644 warp/stats.go create mode 100644 warp/verifier_backend.go create mode 100644 warp/verifier_backend_test.go create mode 100644 warp/wrapped_cache.go diff --git a/go.mod b/go.mod index 08265830d2..e11faaf417 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22.8 require ( github.com/VictoriaMetrics/fastcache v1.12.1 github.com/antithesishq/antithesis-sdk-go v0.3.8 - github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241004185122-5285749cc752 + github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241009195818-ab58a805404b github.com/cespare/cp v0.1.0 github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 github.com/davecgh/go-spew v1.1.1 diff --git a/go.sum b/go.sum index 1693074e83..a2d380588b 100644 --- a/go.sum +++ b/go.sum @@ -60,6 +60,10 @@ github.com/antithesishq/antithesis-sdk-go v0.3.8/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241004185122-5285749cc752 h1:pQh5HA1sf31baNmN6RZpI02JOLmv7o7TcBY4VpuOSMI= github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241004185122-5285749cc752/go.mod h1:qSHmog3wMVjo/ruIAQo0ppXAilyni07NIu5K88RyhWE= +github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241009154434-5d66c421bf61 h1:Emh/obJT0CU4rfS4dkLOFqcHuM66yHFkRynUzFUCX0Q= +github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241009154434-5d66c421bf61/go.mod h1:qSHmog3wMVjo/ruIAQo0ppXAilyni07NIu5K88RyhWE= +github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241009195818-ab58a805404b h1:gYej1NcDzOMGi03rgO0g8UiJVV/eCG33iVqs3HhDw4Y= +github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241009195818-ab58a805404b/go.mod h1:qSHmog3wMVjo/ruIAQo0ppXAilyni07NIu5K88RyhWE= github.com/ava-labs/coreth v0.13.8 h1:f14X3KgwHl9LwzfxlN6S4bbn5VA2rhEsNnHaRLSTo/8= github.com/ava-labs/coreth v0.13.8/go.mod h1:t3BSv/eQv0AlDPMfEDCMMoD/jq1RkUsbFzQAFg5qBcE= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index b874b6e53d..02a9420211 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -16,7 +16,10 @@ import ( "sync" "time" + "github.com/ava-labs/avalanchego/cache" + "github.com/ava-labs/avalanchego/cache/metercacher" "github.com/ava-labs/avalanchego/network/p2p" + "github.com/ava-labs/avalanchego/network/p2p/acp118" "github.com/ava-labs/avalanchego/network/p2p/gossip" "github.com/prometheus/client_golang/prometheus" @@ -44,7 +47,6 @@ import ( statesyncclient "github.com/ava-labs/subnet-evm/sync/client" "github.com/ava-labs/subnet-evm/sync/client/stats" "github.com/ava-labs/subnet-evm/warp" - "github.com/ava-labs/subnet-evm/warp/handlers" // Force-load tracer engine to trigger registration // @@ -70,7 +72,6 @@ import ( "github.com/ava-labs/avalanchego/database/prefixdb" "github.com/ava-labs/avalanchego/database/versiondb" "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/network/p2p/acp118" "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/snow/consensus/snowman" "github.com/ava-labs/avalanchego/snow/engine/snowman/block" @@ -487,13 +488,19 @@ func (vm *VM) Initialize( for i, hexMsg := range vm.config.WarpOffChainMessages { offchainWarpMessages[i] = []byte(hexMsg) } + warpSignatureCache := &cache.LRU[ids.ID, []byte]{Size: warpSignatureCacheSize} + meteredCache, err := metercacher.New("warp_signature_cache", vm.sdkMetrics, warpSignatureCache) + if err != nil { + return fmt.Errorf("failed to create warp signature cache: %w", err) + } + vm.warpBackend, err = warp.NewBackend( vm.ctx.NetworkID, vm.ctx.ChainID, vm.ctx.WarpSigner, vm, vm.warpDB, - warpSignatureCacheSize, + meteredCache, offchainWarpMessages, ) if err != nil { @@ -502,7 +509,7 @@ func (vm *VM) Initialize( // clear warpdb on initialization if config enabled if vm.config.PruneWarpDB { - if err := vm.warpBackend.Clear(); err != nil { + if err := database.Clear(vm.warpDB, ethdb.IdealBatchSize); err != nil { return fmt.Errorf("failed to prune warpDB: %w", err) } } @@ -513,7 +520,16 @@ func (vm *VM) Initialize( go vm.ctx.Log.RecoverAndPanic(vm.startContinuousProfiler) - vm.initializeHandlers() + // Add p2p warp message warpHandler + warpHandler := acp118.NewCachedHandler(meteredCache, vm.warpBackend, vm.ctx.WarpSigner) + vm.Network.AddHandler(p2p.SignatureRequestHandlerID, warpHandler) + + vm.setAppRequestHandlers() + + vm.StateSyncServer = NewStateSyncServer(&stateSyncServerConfig{ + Chain: vm.blockChain, + SyncableInterval: vm.config.StateSyncCommitInterval, + }) return vm.initializeStateSyncClient(lastAcceptedHeight) } @@ -617,22 +633,6 @@ func (vm *VM) initializeStateSyncClient(lastAcceptedHeight uint64) error { return nil } -// initializeHandlers should be called after [vm.chain] is initialized. -func (vm *VM) initializeHandlers() { - vm.StateSyncServer = NewStateSyncServer(&stateSyncServerConfig{ - Chain: vm.blockChain, - SyncableInterval: vm.config.StateSyncCommitInterval, - }) - - // Add p2p warp message warpHandler - signerVerifier := handlers.NewSignerVerifier(vm.warpBackend, vm.networkCodec) - // TODO: consider chancing acp118 handler to take a single Signer interface - warpHandler := acp118.NewHandler(signerVerifier, signerVerifier) - vm.Network.AddHandler(p2p.SignatureRequestHandlerID, warpHandler) - - vm.setAppRequestHandlers() -} - func (vm *VM) initChainState(lastAcceptedBlock *types.Block) error { block := vm.newBlock(lastAcceptedBlock) diff --git a/plugin/evm/vm_warp_test.go b/plugin/evm/vm_warp_test.go index abaf68f4fc..0297f6df62 100644 --- a/plugin/evm/vm_warp_test.go +++ b/plugin/evm/vm_warp_test.go @@ -751,6 +751,8 @@ func TestMessageSignatureRequestsToVM(t *testing.T) { require.NoError(t, err) signature, err := vm.warpBackend.GetMessageSignature(warpMessage) require.NoError(t, err) + var knownSignature [bls.SignatureLen]byte + copy(knownSignature[:], signature) tests := map[string]struct { messageID ids.ID @@ -758,7 +760,7 @@ func TestMessageSignatureRequestsToVM(t *testing.T) { }{ "known": { messageID: warpMessage.ID(), - expectedResponse: signature, + expectedResponse: knownSignature, }, "unknown": { messageID: ids.GenerateTestID(), @@ -807,6 +809,8 @@ func TestBlockSignatureRequestsToVM(t *testing.T) { signature, err := vm.warpBackend.GetBlockSignature(lastAcceptedID) require.NoError(t, err) + var knownSignature [bls.SignatureLen]byte + copy(knownSignature[:], signature) tests := map[string]struct { blockID ids.ID @@ -814,7 +818,7 @@ func TestBlockSignatureRequestsToVM(t *testing.T) { }{ "known": { blockID: lastAcceptedID, - expectedResponse: signature, + expectedResponse: knownSignature, }, "unknown": { blockID: ids.GenerateTestID(), diff --git a/warp/backend.go b/warp/backend.go index b67be9ac70..8d60fee41e 100644 --- a/warp/backend.go +++ b/warp/backend.go @@ -11,21 +11,19 @@ import ( "github.com/ava-labs/avalanchego/cache" "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/network/p2p/acp118" "github.com/ava-labs/avalanchego/snow/consensus/snowman" - "github.com/ava-labs/avalanchego/utils/crypto/bls" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" - "github.com/ava-labs/subnet-evm/warp/messages" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" ) var ( _ Backend = &backend{} errParsingOffChainMessage = errors.New("failed to parse off-chain message") -) -const batchSize = ethdb.IdealBatchSize + messageCacheSize = 500 +) type BlockClient interface { GetAcceptedBlock(ctx context.Context, blockID ids.ID) (snowman.Block, error) @@ -38,30 +36,17 @@ type Backend interface { AddMessage(unsignedMessage *avalancheWarp.UnsignedMessage) error // GetMessageSignature validates the message and returns the signature of the requested message. - GetMessageSignature(message *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) + GetMessageSignature(message *avalancheWarp.UnsignedMessage) ([]byte, error) // GetBlockSignature validates blockID and returns the signature of the requested message hash. - GetBlockSignature(blockID ids.ID) ([bls.SignatureLen]byte, error) + GetBlockSignature(blockID ids.ID) ([]byte, error) // GetMessage retrieves the [unsignedMessage] from the warp backend database if available - // TODO: After E-Upgrade, the backend no longer needs to store the mapping from messageHash + // TODO: After Etna, the backend no longer needs to store the mapping from messageHash // to unsignedMessage (and this method can be removed). GetMessage(messageHash ids.ID) (*avalancheWarp.UnsignedMessage, error) - // ValidateMessage validates the [unsignedMessage] and returns an error if the message is invalid. - ValidateMessage(unsignedMessage *avalancheWarp.UnsignedMessage) error - - // ValidateBlockMessage validates the block message with the given [blockID] and returns an error if the message is invalid. - ValidateBlockMessage(blockID ids.ID) error - - // SignMessage signs the [unsignedMessage] and returns the signature. - SignMessage(unsignedMessage *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) - - // SignBlock signs the block message with the given [blockID] and returns the signature. - SignBlock(blockID ids.ID) ([bls.SignatureLen]byte, error) - - // Clear clears the entire db - Clear() error + acp118.Verifier } // backend implements Backend, keeps track of warp messages, and generates message signatures. @@ -71,10 +56,10 @@ type backend struct { db database.Database warpSigner avalancheWarp.Signer blockClient BlockClient - messageSignatureCache *cache.LRU[ids.ID, [bls.SignatureLen]byte] - blockSignatureCache *cache.LRU[ids.ID, [bls.SignatureLen]byte] + signatureCache cache.Cacher[ids.ID, []byte] messageCache *cache.LRU[ids.ID, *avalancheWarp.UnsignedMessage] offchainAddressedCallMsgs map[ids.ID]*avalancheWarp.UnsignedMessage + stats *verifierStats } // NewBackend creates a new Backend, and initializes the signature cache and message tracking database. @@ -84,18 +69,20 @@ func NewBackend( warpSigner avalancheWarp.Signer, blockClient BlockClient, db database.Database, - cacheSize int, + sdkCache cache.Cacher[ids.ID, []byte], offchainMessages [][]byte, ) (Backend, error) { b := &backend{ - networkID: networkID, - sourceChainID: sourceChainID, - db: db, - warpSigner: warpSigner, - blockClient: blockClient, - messageSignatureCache: &cache.LRU[ids.ID, [bls.SignatureLen]byte]{Size: cacheSize}, - blockSignatureCache: &cache.LRU[ids.ID, [bls.SignatureLen]byte]{Size: cacheSize}, - messageCache: &cache.LRU[ids.ID, *avalancheWarp.UnsignedMessage]{Size: cacheSize}, + networkID: networkID, + sourceChainID: sourceChainID, + db: db, + warpSigner: warpSigner, + blockClient: blockClient, + // sdkCache returns sdk.SignatureResponse proto bytes, + // and it must be wrapped to return Signature bytes. + signatureCache: NewWrappedCache(sdkCache), + messageCache: &cache.LRU[ids.ID, *avalancheWarp.UnsignedMessage]{Size: messageCacheSize}, + stats: newVerifierStats(), offchainAddressedCallMsgs: make(map[ids.ID]*avalancheWarp.UnsignedMessage), } return b, b.initOffChainMessages(offchainMessages) @@ -126,13 +113,6 @@ func (b *backend) initOffChainMessages(offchainMessages [][]byte) error { return nil } -func (b *backend) Clear() error { - b.messageSignatureCache.Flush() - b.blockSignatureCache.Flush() - b.messageCache.Flush() - return database.Clear(b.db, batchSize) -} - func (b *backend) AddMessage(unsignedMessage *avalancheWarp.UnsignedMessage) error { messageID := unsignedMessage.ID() @@ -143,110 +123,56 @@ func (b *backend) AddMessage(unsignedMessage *avalancheWarp.UnsignedMessage) err return fmt.Errorf("failed to put warp signature in db: %w", err) } - var signature [bls.SignatureLen]byte sig, err := b.warpSigner.Sign(unsignedMessage) if err != nil { return fmt.Errorf("failed to sign warp message: %w", err) } - copy(signature[:], sig) - b.messageSignatureCache.Put(messageID, signature) + b.signatureCache.Put(messageID, sig) log.Debug("Adding warp message to backend", "messageID", messageID) return nil } -func (b *backend) GetMessageSignature(unsignedMessage *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) { +func (b *backend) GetMessageSignature(unsignedMessage *avalancheWarp.UnsignedMessage) ([]byte, error) { messageID := unsignedMessage.ID() log.Debug("Getting warp message from backend", "messageID", messageID) - if sig, ok := b.messageSignatureCache.Get(messageID); ok { + if sig, ok := b.signatureCache.Get(messageID); ok { return sig, nil } - if err := b.ValidateMessage(unsignedMessage); err != nil { - return [bls.SignatureLen]byte{}, fmt.Errorf("failed to validate warp message: %w", err) - } - return b.signMessage(unsignedMessage) -} - -func (b *backend) SignMessage(unsignedMessage *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) { - messageID := unsignedMessage.ID() - - if sig, ok := b.messageSignatureCache.Get(messageID); ok { - return sig, nil + if err := b.verifyMessage(unsignedMessage); err != nil { + return []byte{}, fmt.Errorf("failed to validate warp message: %w", err) } - return b.signMessage(unsignedMessage) } -func (b *backend) ValidateMessage(unsignedMessage *avalancheWarp.UnsignedMessage) error { - messageID := unsignedMessage.ID() - - if _, ok := b.messageSignatureCache.Get(messageID); ok { - return nil - } - // Known on-chain messages should be signed - if _, err := b.GetMessage(messageID); err == nil { - return nil - } - - // Try to parse the payload as an AddressedCall - addressedCall, err := payload.ParseAddressedCall(unsignedMessage.Payload) - if err != nil { - return fmt.Errorf("failed to parse unknown message as AddressedCall: %w", err) - } +func (b *backend) GetBlockSignature(blockID ids.ID) ([]byte, error) { + log.Debug("Getting block from backend", "blockID", blockID) - // Further, parse the payload to see if it is a known type. - parsed, err := messages.Parse(addressedCall.Payload) + blockHashPayload, err := payload.NewHash(blockID) if err != nil { - return fmt.Errorf("failed to parse unknown message: %w", err) + return []byte{}, fmt.Errorf("failed to create new block hash payload: %w", err) } - // Check if the message is a known type that can be signed on demand - signable, ok := parsed.(messages.Signable) - if !ok { - return fmt.Errorf("parsed message is not Signable: %T", signable) - } - - // Check if the message should be signed according to its type - if err := signable.VerifyMesssage(addressedCall.SourceAddress); err != nil { - return fmt.Errorf("failed to verify Signable message: %w", err) - } - return nil -} - -func (b *backend) ValidateBlockMessage(blockID ids.ID) error { - if _, ok := b.blockSignatureCache.Get(blockID); ok { - return nil - } - - _, err := b.blockClient.GetAcceptedBlock(context.TODO(), blockID) + unsignedMessage, err := avalancheWarp.NewUnsignedMessage(b.networkID, b.sourceChainID, blockHashPayload.Bytes()) if err != nil { - return fmt.Errorf("failed to get block %s: %w", blockID, err) + return []byte{}, fmt.Errorf("failed to create new unsigned warp message: %w", err) } - return nil -} - -func (b *backend) GetBlockSignature(blockID ids.ID) ([bls.SignatureLen]byte, error) { - log.Debug("Getting block from backend", "blockID", blockID) - if sig, ok := b.blockSignatureCache.Get(blockID); ok { + if sig, ok := b.signatureCache.Get(unsignedMessage.ID()); ok { return sig, nil } - if err := b.ValidateBlockMessage(blockID); err != nil { - return [bls.SignatureLen]byte{}, fmt.Errorf("failed to validate block message: %w", err) + if err := b.verifyBlockMessage(blockHashPayload); err != nil { + return []byte{}, fmt.Errorf("failed to validate block message: %w", err) } - return b.signBlock(blockID) -} - -func (b *backend) SignBlock(blockID ids.ID) ([bls.SignatureLen]byte, error) { - if sig, ok := b.blockSignatureCache.Get(blockID); ok { - return sig, nil + sig, err := b.signMessage(unsignedMessage) + if err != nil { + return []byte{}, fmt.Errorf("failed to sign block message: %w", err) } - - return b.signBlock(blockID) + return sig, nil } func (b *backend) GetMessage(messageID ids.ID) (*avalancheWarp.UnsignedMessage, error) { @@ -271,34 +197,12 @@ func (b *backend) GetMessage(messageID ids.ID) (*avalancheWarp.UnsignedMessage, return unsignedMessage, nil } -func (b *backend) signMessage(unsignedMessage *avalancheWarp.UnsignedMessage) ([bls.SignatureLen]byte, error) { - sig, err := b.warpSigner.Sign(unsignedMessage) - if err != nil { - return [bls.SignatureLen]byte{}, fmt.Errorf("failed to sign warp message: %w", err) - } - - var signature [bls.SignatureLen]byte - copy(signature[:], sig) - b.messageSignatureCache.Put(unsignedMessage.ID(), signature) - return signature, nil -} - -func (b *backend) signBlock(blockID ids.ID) ([bls.SignatureLen]byte, error) { - blockHashPayload, err := payload.NewHash(blockID) - if err != nil { - return [bls.SignatureLen]byte{}, fmt.Errorf("failed to create new block hash payload: %w", err) - } - unsignedMessage, err := avalancheWarp.NewUnsignedMessage(b.networkID, b.sourceChainID, blockHashPayload.Bytes()) - if err != nil { - return [bls.SignatureLen]byte{}, fmt.Errorf("failed to create new unsigned warp message: %w", err) - } +func (b *backend) signMessage(unsignedMessage *avalancheWarp.UnsignedMessage) ([]byte, error) { sig, err := b.warpSigner.Sign(unsignedMessage) if err != nil { - return [bls.SignatureLen]byte{}, fmt.Errorf("failed to sign warp message: %w", err) + return []byte{}, fmt.Errorf("failed to sign warp message: %w", err) } - var signature [bls.SignatureLen]byte - copy(signature[:], sig) - b.blockSignatureCache.Put(blockID, signature) - return signature, nil + b.signatureCache.Put(unsignedMessage.ID(), sig) + return sig, nil } diff --git a/warp/backend_test.go b/warp/backend_test.go index 21013dfc24..91129bd104 100644 --- a/warp/backend_test.go +++ b/warp/backend_test.go @@ -6,6 +6,7 @@ package warp import ( "testing" + "github.com/ava-labs/avalanchego/cache" "github.com/ava-labs/avalanchego/database/memdb" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils" @@ -35,56 +36,14 @@ func init() { } } -func TestClearDB(t *testing.T) { - db := memdb.New() - - sk, err := bls.NewSecretKey() - require.NoError(t, err) - warpSigner := avalancheWarp.NewSigner(sk, networkID, sourceChainID) - backendIntf, err := NewBackend(networkID, sourceChainID, warpSigner, nil, db, 500, nil) - require.NoError(t, err) - backend, ok := backendIntf.(*backend) - require.True(t, ok) - - // use multiple messages to test that all messages get cleared - payloads := [][]byte{[]byte("test1"), []byte("test2"), []byte("test3"), []byte("test4"), []byte("test5")} - messages := make([]*avalancheWarp.UnsignedMessage, 0, len(payloads)) - - // add all messages - for _, payload := range payloads { - unsignedMsg, err := avalancheWarp.NewUnsignedMessage(networkID, sourceChainID, payload) - require.NoError(t, err) - messages = append(messages, unsignedMsg) - err = backend.AddMessage(unsignedMsg) - require.NoError(t, err) - // ensure that the message was added - _, err = backend.GetMessageSignature(unsignedMsg) - require.NoError(t, err) - } - - err = backend.Clear() - require.NoError(t, err) - require.Zero(t, backend.messageCache.Len()) - require.Zero(t, backend.messageSignatureCache.Len()) - require.Zero(t, backend.blockSignatureCache.Len()) - it := db.NewIterator() - defer it.Release() - require.False(t, it.Next()) - - // ensure all messages have been deleted - for _, message := range messages { - _, err := backend.GetMessageSignature(message) - require.ErrorContains(t, err, "failed to validate warp message") - } -} - func TestAddAndGetValidMessage(t *testing.T) { db := memdb.New() sk, err := bls.NewSecretKey() require.NoError(t, err) warpSigner := avalancheWarp.NewSigner(sk, networkID, sourceChainID) - backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, db, 500, nil) + messageSignatureCache := &cache.LRU[ids.ID, []byte]{Size: 500} + backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, db, messageSignatureCache, nil) require.NoError(t, err) // Add testUnsignedMessage to the warp backend @@ -106,7 +65,8 @@ func TestAddAndGetUnknownMessage(t *testing.T) { sk, err := bls.NewSecretKey() require.NoError(t, err) warpSigner := avalancheWarp.NewSigner(sk, networkID, sourceChainID) - backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, db, 500, nil) + messageSignatureCache := &cache.LRU[ids.ID, []byte]{Size: 500} + backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, db, messageSignatureCache, nil) require.NoError(t, err) // Try getting a signature for a message that was not added. @@ -124,7 +84,8 @@ func TestGetBlockSignature(t *testing.T) { sk, err := bls.NewSecretKey() require.NoError(err) warpSigner := avalancheWarp.NewSigner(sk, networkID, sourceChainID) - backend, err := NewBackend(networkID, sourceChainID, warpSigner, blockClient, db, 500, nil) + messageSignatureCache := &cache.LRU[ids.ID, []byte]{} + backend, err := NewBackend(networkID, sourceChainID, warpSigner, blockClient, db, messageSignatureCache, nil) require.NoError(err) blockHashPayload, err := payload.NewHash(blkID) @@ -150,7 +111,8 @@ func TestZeroSizedCache(t *testing.T) { warpSigner := avalancheWarp.NewSigner(sk, networkID, sourceChainID) // Verify zero sized cache works normally, because the lru cache will be initialized to size 1 for any size parameter <= 0. - backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, db, 0, nil) + messageSignatureCache := &cache.LRU[ids.ID, []byte]{Size: 0} + backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, db, messageSignatureCache, nil) require.NoError(t, err) // Add testUnsignedMessage to the warp backend @@ -203,7 +165,8 @@ func TestOffChainMessages(t *testing.T) { require := require.New(t) db := memdb.New() - backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, db, 0, test.offchainMessages) + messageSignatureCache := &cache.LRU[ids.ID, []byte]{Size: 500} + backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, db, messageSignatureCache, test.offchainMessages) require.ErrorIs(err, test.err) if test.check != nil { test.check(require, backend) diff --git a/warp/handlers/signature_request.go b/warp/handlers/signature_request.go index 3a28cd994e..1799774b5c 100644 --- a/warp/handlers/signature_request.go +++ b/warp/handlers/signature_request.go @@ -16,7 +16,7 @@ import ( ) // SignatureRequestHandler serves warp signature requests. It is a peer.RequestHandler for message.MessageSignatureRequest. -// TODO: After E-Upgrade, this handler can be removed and SignatureRequestHandlerP2P is sufficient. +// TODO: After Etna, this handler can be removed and SignatureRequestHandlerP2P is sufficient. type SignatureRequestHandler struct { backend warp.Backend codec codec.Manager @@ -51,13 +51,14 @@ func (s *SignatureRequestHandler) OnMessageSignatureRequest(ctx context.Context, log.Debug("Unknown warp message requested", "messageID", signatureRequest.MessageID) s.stats.IncMessageSignatureMiss() } else { - signature, err = s.backend.GetMessageSignature(unsignedMessage) + sig, err := s.backend.GetMessageSignature(unsignedMessage) if err != nil { log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) s.stats.IncMessageSignatureMiss() signature = [bls.SignatureLen]byte{} } else { s.stats.IncMessageSignatureHit() + copy(signature[:], sig) } } @@ -80,13 +81,15 @@ func (s *SignatureRequestHandler) OnBlockSignatureRequest(ctx context.Context, n s.stats.UpdateBlockSignatureRequestTime(time.Since(startTime)) }() - signature, err := s.backend.GetBlockSignature(request.BlockID) + var signature [bls.SignatureLen]byte + sig, err := s.backend.GetBlockSignature(request.BlockID) if err != nil { log.Debug("Unknown warp signature requested", "blockID", request.BlockID) s.stats.IncBlockSignatureMiss() signature = [bls.SignatureLen]byte{} } else { s.stats.IncBlockSignatureHit() + copy(signature[:], sig) } response := message.SignatureResponse{Signature: signature} diff --git a/warp/handlers/signature_request_test.go b/warp/handlers/signature_request_test.go index 455ac268e2..8320b9cea1 100644 --- a/warp/handlers/signature_request_test.go +++ b/warp/handlers/signature_request_test.go @@ -7,6 +7,7 @@ import ( "context" "testing" + "github.com/ava-labs/avalanchego/cache" "github.com/ava-labs/avalanchego/database/memdb" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/crypto/bls" @@ -31,7 +32,8 @@ func TestMessageSignatureHandler(t *testing.T) { offchainMessage, err := avalancheWarp.NewUnsignedMessage(snowCtx.NetworkID, snowCtx.ChainID, addressedPayload.Bytes()) require.NoError(t, err) - backend, err := warp.NewBackend(snowCtx.NetworkID, snowCtx.ChainID, warpSigner, warptest.EmptyBlockClient, database, 100, [][]byte{offchainMessage.Bytes()}) + messageSignatureCache := &cache.LRU[ids.ID, []byte]{Size: 100} + backend, err := warp.NewBackend(snowCtx.NetworkID, snowCtx.ChainID, warpSigner, warptest.EmptyBlockClient, database, messageSignatureCache, [][]byte{offchainMessage.Bytes()}) require.NoError(t, err) msg, err := avalancheWarp.NewUnsignedMessage(snowCtx.NetworkID, snowCtx.ChainID, []byte("test")) @@ -131,13 +133,14 @@ func TestBlockSignatureHandler(t *testing.T) { warpSigner := avalancheWarp.NewSigner(blsSecretKey, snowCtx.NetworkID, snowCtx.ChainID) blkID := ids.GenerateTestID() blockClient := warptest.MakeBlockClient(blkID) + messageSignatureCache := &cache.LRU[ids.ID, []byte]{Size: 100} backend, err := warp.NewBackend( snowCtx.NetworkID, snowCtx.ChainID, warpSigner, blockClient, database, - 100, + messageSignatureCache, nil, ) require.NoError(t, err) diff --git a/warp/handlers/signer_verifier_p2p.go b/warp/handlers/signer_verifier_p2p.go deleted file mode 100644 index 6237217ee2..0000000000 --- a/warp/handlers/signer_verifier_p2p.go +++ /dev/null @@ -1,156 +0,0 @@ -// (c) 2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package handlers - -import ( - "context" - "fmt" - "time" - - "github.com/ava-labs/avalanchego/codec" - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/network/p2p/acp118" - "github.com/ava-labs/avalanchego/snow/engine/common" - avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" - "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" - "github.com/ava-labs/subnet-evm/warp" -) - -var ( - _ avalancheWarp.Signer = (*p2pSignerVerifier)(nil) - _ acp118.Verifier = (*p2pSignerVerifier)(nil) -) - -const ( - ParseErrCode = iota - GetSigErrCode - MarshalErrCode - ValidateErrCode -) - -var ( - errUnknownPayloadType = fmt.Errorf("unknown payload type") - errFailedToParse = fmt.Errorf("failed to parse payload") - errFailedToGetSig = fmt.Errorf("failed to get signature") -) - -type SignerVerifier interface { - acp118.Verifier - avalancheWarp.Signer -} - -// p2pSignerVerifier serves warp signature requests using the p2p -// framework from avalanchego. It is a peer.RequestHandler for -// message.MessageSignatureRequest. -type p2pSignerVerifier struct { - backend warp.Backend - codec codec.Manager - stats *handlerStats -} - -func NewSignerVerifier(backend warp.Backend, codec codec.Manager) SignerVerifier { - return &p2pSignerVerifier{ - backend: backend, - codec: codec, - stats: newStats(), - } -} - -func (s *p2pSignerVerifier) Verify(_ context.Context, unsignedMessage *avalancheWarp.UnsignedMessage, _ []byte) *common.AppError { - parsed, err := payload.Parse(unsignedMessage.Payload) - if err != nil { - return &common.AppError{ - Code: ParseErrCode, - Message: "failed to parse payload: " + err.Error(), - } - } - - switch p := parsed.(type) { - case *payload.AddressedCall: - err = s.backend.ValidateMessage(unsignedMessage) - if err != nil { - s.stats.IncMessageSignatureValidationFail() - return &common.AppError{ - Code: ValidateErrCode, - Message: "failed to validate message: " + err.Error(), - } - } - case *payload.Hash: - err = s.backend.ValidateBlockMessage(p.Hash) - if err != nil { - s.stats.IncBlockSignatureValidationFail() - return &common.AppError{ - Code: ValidateErrCode, - Message: "failed to validate block message: " + err.Error(), - } - } - default: - return &common.AppError{ - Code: ParseErrCode, - Message: fmt.Sprintf("unknown payload type: %T", p), - } - } - return nil -} - -func (s *p2pSignerVerifier) Sign(unsignedMessage *avalancheWarp.UnsignedMessage) ([]byte, error) { - parsed, err := payload.Parse(unsignedMessage.Payload) - if err != nil { - return nil, fmt.Errorf("%w: %s", errFailedToParse, err.Error()) - } - - var sig []byte - switch p := parsed.(type) { - case *payload.AddressedCall: - sig, err = s.GetMessageSignature(unsignedMessage) - if err != nil { - s.stats.IncMessageSignatureMiss() - } else { - s.stats.IncMessageSignatureHit() - } - case *payload.Hash: - sig, err = s.GetBlockSignature(p.Hash) - if err != nil { - s.stats.IncBlockSignatureMiss() - } else { - s.stats.IncBlockSignatureHit() - } - default: - return nil, fmt.Errorf("%w: %T", errUnknownPayloadType, p) - } - - if err != nil { - return nil, fmt.Errorf("%w: %s", errFailedToGetSig, err.Error()) - } - - return sig, nil -} - -func (s *p2pSignerVerifier) GetMessageSignature(message *avalancheWarp.UnsignedMessage) ([]byte, error) { - startTime := time.Now() - s.stats.IncMessageSignatureRequest() - - // Always report signature request time - defer func() { - s.stats.UpdateMessageSignatureRequestTime(time.Since(startTime)) - }() - - // TODO: consider changing backend to return []byte - sig, err := s.backend.SignMessage(message) - return sig[:], err -} - -func (s *p2pSignerVerifier) GetBlockSignature(blockID ids.ID) ([]byte, error) { - startTime := time.Now() - s.stats.IncBlockSignatureRequest() - - // Always report signature request time - defer func() { - s.stats.UpdateBlockSignatureRequestTime(time.Since(startTime)) - }() - - // TODO: consider changing backend to return []byte - sig, err := s.backend.SignBlock(blockID) - return sig[:], err -} diff --git a/warp/handlers/signer_verifier_p2p_test.go b/warp/handlers/signer_verifier_p2p_test.go deleted file mode 100644 index 76eba68317..0000000000 --- a/warp/handlers/signer_verifier_p2p_test.go +++ /dev/null @@ -1,242 +0,0 @@ -// (c) 2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package handlers - -import ( - "context" - "testing" - "time" - - "github.com/ava-labs/avalanchego/database/memdb" - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/network/p2p/acp118" - "github.com/ava-labs/avalanchego/proto/pb/sdk" - "github.com/ava-labs/avalanchego/snow/engine/common" - "github.com/ava-labs/avalanchego/utils/crypto/bls" - avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" - "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" - "github.com/ava-labs/subnet-evm/plugin/evm/message" - "github.com/ava-labs/subnet-evm/utils" - "github.com/ava-labs/subnet-evm/warp" - "github.com/ava-labs/subnet-evm/warp/warptest" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestMessageSignatures(t *testing.T) { - database := memdb.New() - snowCtx := utils.TestSnowContext() - blsSecretKey, err := bls.NewSecretKey() - require.NoError(t, err) - warpSigner := avalancheWarp.NewSigner(blsSecretKey, snowCtx.NetworkID, snowCtx.ChainID) - - addressedPayload, err := payload.NewAddressedCall([]byte{1, 2, 3}, []byte{1, 2, 3}) - require.NoError(t, err) - offchainMessage, err := avalancheWarp.NewUnsignedMessage(snowCtx.NetworkID, snowCtx.ChainID, addressedPayload.Bytes()) - require.NoError(t, err) - - backend, err := warp.NewBackend(snowCtx.NetworkID, snowCtx.ChainID, warpSigner, warptest.EmptyBlockClient, database, 100, [][]byte{offchainMessage.Bytes()}) - require.NoError(t, err) - - offchainPayload, err := payload.NewAddressedCall([]byte{0, 0, 0}, []byte("test")) - require.NoError(t, err) - msg, err := avalancheWarp.NewUnsignedMessage(snowCtx.NetworkID, snowCtx.ChainID, offchainPayload.Bytes()) - require.NoError(t, err) - require.NoError(t, backend.AddMessage(msg)) - signature, err := backend.GetMessageSignature(msg) - require.NoError(t, err) - offchainSignature, err := backend.GetMessageSignature(offchainMessage) - require.NoError(t, err) - - unknownPayload, err := payload.NewAddressedCall([]byte{0, 0, 0}, []byte("unknown message")) - require.NoError(t, err) - unknownMessage, err := avalancheWarp.NewUnsignedMessage(snowCtx.NetworkID, snowCtx.ChainID, unknownPayload.Bytes()) - require.NoError(t, err) - - tests := map[string]struct { - setup func() (request sdk.SignatureRequest, expectedResponse []byte) - verifyStats func(t *testing.T, stats *handlerStats) - err error - }{ - "known message": { - setup: func() (request sdk.SignatureRequest, expectedResponse []byte) { - return sdk.SignatureRequest{Message: msg.Bytes()}, signature[:] - }, - verifyStats: func(t *testing.T, stats *handlerStats) { - require.EqualValues(t, 1, stats.messageSignatureRequest.Snapshot().Count()) - require.EqualValues(t, 0, stats.messageSignatureValidationFail.Snapshot().Count()) - require.EqualValues(t, 1, stats.messageSignatureHit.Snapshot().Count()) - require.EqualValues(t, 0, stats.messageSignatureMiss.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureRequest.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureHit.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureMiss.Snapshot().Count()) - }, - }, - "offchain message": { - setup: func() (request sdk.SignatureRequest, expectedResponse []byte) { - return sdk.SignatureRequest{Message: offchainMessage.Bytes()}, offchainSignature[:] - }, - verifyStats: func(t *testing.T, stats *handlerStats) { - require.EqualValues(t, 1, stats.messageSignatureRequest.Snapshot().Count()) - require.EqualValues(t, 0, stats.messageSignatureValidationFail.Snapshot().Count()) - require.EqualValues(t, 1, stats.messageSignatureHit.Snapshot().Count()) - require.EqualValues(t, 0, stats.messageSignatureMiss.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureRequest.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureHit.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureMiss.Snapshot().Count()) - }, - }, - "unknown message": { - setup: func() (request sdk.SignatureRequest, expectedResponse []byte) { - return sdk.SignatureRequest{Message: unknownMessage.Bytes()}, nil - }, - verifyStats: func(t *testing.T, stats *handlerStats) { - require.EqualValues(t, 0, stats.messageSignatureRequest.Snapshot().Count()) - require.EqualValues(t, 1, stats.messageSignatureValidationFail.Snapshot().Count()) - require.EqualValues(t, 0, stats.messageSignatureHit.Snapshot().Count()) - require.EqualValues(t, 0, stats.messageSignatureMiss.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureRequest.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureHit.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureMiss.Snapshot().Count()) - }, - err: &common.AppError{Code: ValidateErrCode}, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - signerVerifier := NewSignerVerifier(backend, message.Codec) - handler := acp118.NewHandler(signerVerifier, signerVerifier) - - request, expectedResponse := test.setup() - requestBytes, err := proto.Marshal(&request) - require.NoError(t, err) - responseBytes, appErr := handler.AppRequest(context.Background(), ids.GenerateTestNodeID(), time.Time{}, requestBytes) - if test.err != nil { - require.ErrorIs(t, appErr, test.err) - } else { - require.Nil(t, appErr) - } - - test.verifyStats(t, signerVerifier.(*p2pSignerVerifier).stats) - - // If the expected response is empty, assert that the handler returns an empty response and return early. - if len(expectedResponse) == 0 { - require.Len(t, responseBytes, 0, "expected response to be empty") - return - } - var response sdk.SignatureResponse - err = proto.Unmarshal(responseBytes, &response) - require.NoError(t, err, "error unmarshalling SignatureResponse") - - require.Equal(t, expectedResponse, response.Signature) - }) - } -} - -func TestBlockSignatures(t *testing.T) { - database := memdb.New() - snowCtx := utils.TestSnowContext() - blsSecretKey, err := bls.NewSecretKey() - require.NoError(t, err) - - warpSigner := avalancheWarp.NewSigner(blsSecretKey, snowCtx.NetworkID, snowCtx.ChainID) - blkID := ids.GenerateTestID() - blockClient := warptest.MakeBlockClient(blkID) - backend, err := warp.NewBackend( - snowCtx.NetworkID, - snowCtx.ChainID, - warpSigner, - blockClient, - database, - 100, - nil, - ) - require.NoError(t, err) - - signature, err := backend.GetBlockSignature(blkID) - require.NoError(t, err) - unknownBlockID := ids.GenerateTestID() - - toMessageBytes := func(id ids.ID) []byte { - idPayload, err := payload.NewHash(id) - require.NoError(t, err) - - msg, err := avalancheWarp.NewUnsignedMessage(snowCtx.NetworkID, snowCtx.ChainID, idPayload.Bytes()) - require.NoError(t, err) - - return msg.Bytes() - } - - tests := map[string]struct { - setup func() (request sdk.SignatureRequest, expectedResponse []byte) - verifyStats func(t *testing.T, stats *handlerStats) - err error - }{ - "known block": { - setup: func() (request sdk.SignatureRequest, expectedResponse []byte) { - return sdk.SignatureRequest{Message: toMessageBytes(blkID)}, signature[:] - }, - verifyStats: func(t *testing.T, stats *handlerStats) { - require.EqualValues(t, 0, stats.messageSignatureRequest.Snapshot().Count()) - require.EqualValues(t, 0, stats.messageSignatureValidationFail.Snapshot().Count()) - require.EqualValues(t, 0, stats.messageSignatureHit.Snapshot().Count()) - require.EqualValues(t, 0, stats.messageSignatureMiss.Snapshot().Count()) - require.EqualValues(t, 1, stats.blockSignatureRequest.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) - require.EqualValues(t, 1, stats.blockSignatureHit.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureMiss.Snapshot().Count()) - }, - }, - "unknown block": { - setup: func() (request sdk.SignatureRequest, expectedResponse []byte) { - return sdk.SignatureRequest{Message: toMessageBytes(unknownBlockID)}, nil - }, - verifyStats: func(t *testing.T, stats *handlerStats) { - require.EqualValues(t, 0, stats.messageSignatureRequest.Snapshot().Count()) - require.EqualValues(t, 0, stats.messageSignatureValidationFail.Snapshot().Count()) - require.EqualValues(t, 0, stats.messageSignatureHit.Snapshot().Count()) - require.EqualValues(t, 0, stats.messageSignatureMiss.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureRequest.Snapshot().Count()) - require.EqualValues(t, 1, stats.blockSignatureValidationFail.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureHit.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureMiss.Snapshot().Count()) - }, - err: &common.AppError{Code: ValidateErrCode}, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - signerVerifier := NewSignerVerifier(backend, message.Codec) - handler := acp118.NewHandler(signerVerifier, signerVerifier) - - request, expectedResponse := test.setup() - requestBytes, err := proto.Marshal(&request) - require.NoError(t, err) - responseBytes, appErr := handler.AppRequest(context.Background(), ids.GenerateTestNodeID(), time.Time{}, requestBytes) - if test.err != nil { - require.ErrorIs(t, appErr, test.err) - } else { - require.Nil(t, appErr) - } - - test.verifyStats(t, signerVerifier.(*p2pSignerVerifier).stats) - - // If the expected response is empty, assert that the handler returns an empty response and return early. - if len(expectedResponse) == 0 { - require.Len(t, responseBytes, 0, "expected response to be empty") - return - } - var response sdk.SignatureResponse - err = proto.Unmarshal(responseBytes, &response) - require.NoError(t, err, "error unmarshalling SignatureResponse") - - require.Equal(t, expectedResponse, response.Signature) - }) - } -} diff --git a/warp/handlers/stats.go b/warp/handlers/stats.go index 545013fcd3..1c7a854e97 100644 --- a/warp/handlers/stats.go +++ b/warp/handlers/stats.go @@ -12,13 +12,11 @@ import ( type handlerStats struct { // MessageSignatureRequestHandler metrics messageSignatureRequest metrics.Counter - messageSignatureValidationFail metrics.Counter messageSignatureHit metrics.Counter messageSignatureMiss metrics.Counter messageSignatureRequestDuration metrics.Gauge // BlockSignatureRequestHandler metrics blockSignatureRequest metrics.Counter - blockSignatureValidationFail metrics.Counter blockSignatureHit metrics.Counter blockSignatureMiss metrics.Counter blockSignatureRequestDuration metrics.Gauge @@ -27,12 +25,10 @@ type handlerStats struct { func newStats() *handlerStats { return &handlerStats{ messageSignatureRequest: metrics.NewRegisteredCounter("message_signature_request_count", nil), - messageSignatureValidationFail: metrics.NewRegisteredCounter("message_signature_request_validation_fail", nil), messageSignatureHit: metrics.NewRegisteredCounter("message_signature_request_hit", nil), messageSignatureMiss: metrics.NewRegisteredCounter("message_signature_request_miss", nil), messageSignatureRequestDuration: metrics.NewRegisteredGauge("message_signature_request_duration", nil), blockSignatureRequest: metrics.NewRegisteredCounter("block_signature_request_count", nil), - blockSignatureValidationFail: metrics.NewRegisteredCounter("block_signature_request_validation_fail", nil), blockSignatureHit: metrics.NewRegisteredCounter("block_signature_request_hit", nil), blockSignatureMiss: metrics.NewRegisteredCounter("block_signature_request_miss", nil), blockSignatureRequestDuration: metrics.NewRegisteredGauge("block_signature_request_duration", nil), @@ -40,20 +36,14 @@ func newStats() *handlerStats { } func (h *handlerStats) IncMessageSignatureRequest() { h.messageSignatureRequest.Inc(1) } -func (h *handlerStats) IncMessageSignatureValidationFail() { - h.messageSignatureValidationFail.Inc(1) -} -func (h *handlerStats) IncMessageSignatureHit() { h.messageSignatureHit.Inc(1) } -func (h *handlerStats) IncMessageSignatureMiss() { h.messageSignatureMiss.Inc(1) } +func (h *handlerStats) IncMessageSignatureHit() { h.messageSignatureHit.Inc(1) } +func (h *handlerStats) IncMessageSignatureMiss() { h.messageSignatureMiss.Inc(1) } func (h *handlerStats) UpdateMessageSignatureRequestTime(duration time.Duration) { h.messageSignatureRequestDuration.Inc(int64(duration)) } func (h *handlerStats) IncBlockSignatureRequest() { h.blockSignatureRequest.Inc(1) } -func (h *handlerStats) IncBlockSignatureValidationFail() { - h.blockSignatureValidationFail.Inc(1) -} -func (h *handlerStats) IncBlockSignatureHit() { h.blockSignatureHit.Inc(1) } -func (h *handlerStats) IncBlockSignatureMiss() { h.blockSignatureMiss.Inc(1) } +func (h *handlerStats) IncBlockSignatureHit() { h.blockSignatureHit.Inc(1) } +func (h *handlerStats) IncBlockSignatureMiss() { h.blockSignatureMiss.Inc(1) } func (h *handlerStats) UpdateBlockSignatureRequestTime(duration time.Duration) { h.blockSignatureRequestDuration.Inc(int64(duration)) } diff --git a/warp/messages/payload.go b/warp/messages/payload.go index 3776a1356d..facf54524d 100644 --- a/warp/messages/payload.go +++ b/warp/messages/payload.go @@ -20,12 +20,6 @@ type Payload interface { initialize(b []byte) } -// Signable is an optional interface that payloads can implement to allow -// on-the-fly signing of incoming messages by the warp backend. -type Signable interface { - VerifyMesssage(sourceAddress []byte) error -} - func Parse(bytes []byte) (Payload, error) { var payload Payload if _, err := Codec.Unmarshal(bytes, &payload); err != nil { diff --git a/warp/stats.go b/warp/stats.go new file mode 100644 index 0000000000..7135670f13 --- /dev/null +++ b/warp/stats.go @@ -0,0 +1,36 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package warp + +import ( + "github.com/ava-labs/subnet-evm/metrics" +) + +type verifierStats struct { + messageParseFail metrics.Counter + // AddressedCall metrics + addressedCallSignatureValidationFail metrics.Counter + // BlockRequest metrics + blockSignatureValidationFail metrics.Counter +} + +func newVerifierStats() *verifierStats { + return &verifierStats{ + messageParseFail: metrics.NewRegisteredCounter("message_parse_fail", nil), + addressedCallSignatureValidationFail: metrics.NewRegisteredCounter("addressed_call_signature_validation_fail", nil), + blockSignatureValidationFail: metrics.NewRegisteredCounter("block_signature_validation_fail", nil), + } +} + +func (h *verifierStats) IncAddressedCallSignatureValidationFail() { + h.addressedCallSignatureValidationFail.Inc(1) +} + +func (h *verifierStats) IncBlockSignatureValidationFail() { + h.blockSignatureValidationFail.Inc(1) +} + +func (h *verifierStats) IncMessageParseFail() { + h.messageParseFail.Inc(1) +} diff --git a/warp/verifier_backend.go b/warp/verifier_backend.go new file mode 100644 index 0000000000..64249bbba6 --- /dev/null +++ b/warp/verifier_backend.go @@ -0,0 +1,105 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package warp + +import ( + "context" + "fmt" + + "github.com/ava-labs/subnet-evm/warp/messages" + + "github.com/ava-labs/avalanchego/snow/engine/common" + avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" + "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" +) + +const ( + ParseErrCode = iota + 1 + VerifyErrCode +) + +// Verify implements the acp118.Verifier interface +func (b *backend) Verify(_ context.Context, unsignedMessage *avalancheWarp.UnsignedMessage, _ []byte) *common.AppError { + if err := b.verifyMessage(unsignedMessage); err != nil { + return err + } + return nil +} + +// verifyMessage verifies the signature of the message +// This is moved to a separate function to avoid having to use a context.Context +func (b *backend) verifyMessage(unsignedMessage *avalancheWarp.UnsignedMessage) *common.AppError { + messageID := unsignedMessage.ID() + // Known on-chain messages should be signed + if _, err := b.GetMessage(messageID); err == nil { + return nil + } + + parsed, err := payload.Parse(unsignedMessage.Payload) + if err != nil { + b.stats.IncMessageParseFail() + return &common.AppError{ + Code: ParseErrCode, + Message: "failed to parse payload: " + err.Error(), + } + } + + switch p := parsed.(type) { + case *payload.AddressedCall: + apperr := b.verifyAddressedCall(p) + if apperr != nil { + b.stats.IncAddressedCallSignatureValidationFail() + return apperr + } + case *payload.Hash: + apperr := b.verifyBlockMessage(p) + if apperr != nil { + b.stats.IncBlockSignatureValidationFail() + return apperr + } + default: + b.stats.IncMessageParseFail() + return &common.AppError{ + Code: ParseErrCode, + Message: fmt.Sprintf("unknown payload type: %T", p), + } + } + return nil +} + +// verifyBlockMessage verifies the block message (payload.Hash) +func (b *backend) verifyBlockMessage(blockHashPayload *payload.Hash) *common.AppError { + blockID := blockHashPayload.Hash + _, err := b.blockClient.GetAcceptedBlock(context.TODO(), blockID) + if err != nil { + return &common.AppError{ + Code: VerifyErrCode, + Message: fmt.Sprintf("failed to get block %s: %s", blockID, err.Error()), + } + } + + return nil +} + +// verifyAddressedCall verifies the addressed call message +func (b *backend) verifyAddressedCall(addressedCall *payload.AddressedCall) *common.AppError { + // Further, parse the payload to see if it is a known type. + parsed, err := messages.Parse(addressedCall.Payload) + if err != nil { + return &common.AppError{ + Code: ParseErrCode, + Message: "failed to parse addressed call message: " + err.Error(), + } + } + + switch p := parsed.(type) { + case *messages.ValidatorUptime: + return nil + default: + return &common.AppError{ + Code: ParseErrCode, + Message: fmt.Sprintf("unknown message type: %T", p), + } + } +} diff --git a/warp/verifier_backend_test.go b/warp/verifier_backend_test.go new file mode 100644 index 0000000000..6b0c120db6 --- /dev/null +++ b/warp/verifier_backend_test.go @@ -0,0 +1,222 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package warp + +import ( + "context" + "testing" + "time" + + "github.com/ava-labs/avalanchego/cache" + "github.com/ava-labs/avalanchego/database/memdb" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/network/p2p/acp118" + "github.com/ava-labs/avalanchego/proto/pb/sdk" + "github.com/ava-labs/avalanchego/snow/engine/common" + "github.com/ava-labs/avalanchego/utils/crypto/bls" + avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" + "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + "github.com/ava-labs/subnet-evm/utils" + "github.com/ava-labs/subnet-evm/warp/warptest" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" +) + +func TestAddressedCallSignatures(t *testing.T) { + database := memdb.New() + snowCtx := utils.TestSnowContext() + blsSecretKey, err := bls.NewSecretKey() + require.NoError(t, err) + warpSigner := avalancheWarp.NewSigner(blsSecretKey, snowCtx.NetworkID, snowCtx.ChainID) + + offChainPayload, err := payload.NewAddressedCall([]byte{1, 2, 3}, []byte{1, 2, 3}) + require.NoError(t, err) + offchainMessage, err := avalancheWarp.NewUnsignedMessage(snowCtx.NetworkID, snowCtx.ChainID, offChainPayload.Bytes()) + require.NoError(t, err) + offchainSignature, err := warpSigner.Sign(offchainMessage) + require.NoError(t, err) + + tests := map[string]struct { + setup func(backend Backend) (request []byte, expectedResponse []byte) + verifyStats func(t *testing.T, stats *verifierStats) + err error + }{ + "known message": { + setup: func(backend Backend) (request []byte, expectedResponse []byte) { + knownPayload, err := payload.NewAddressedCall([]byte{0, 0, 0}, []byte("test")) + require.NoError(t, err) + msg, err := avalancheWarp.NewUnsignedMessage(snowCtx.NetworkID, snowCtx.ChainID, knownPayload.Bytes()) + require.NoError(t, err) + offchainSignature, err := warpSigner.Sign(msg) + require.NoError(t, err) + + backend.AddMessage(msg) + return msg.Bytes(), offchainSignature[:] + }, + verifyStats: func(t *testing.T, stats *verifierStats) { + require.EqualValues(t, 0, stats.messageParseFail.Snapshot().Count()) + require.EqualValues(t, 0, stats.addressedCallSignatureValidationFail.Snapshot().Count()) + require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) + }, + }, + "offchain message": { + setup: func(_ Backend) (request []byte, expectedResponse []byte) { + return offchainMessage.Bytes(), offchainSignature[:] + }, + verifyStats: func(t *testing.T, stats *verifierStats) { + require.EqualValues(t, 0, stats.messageParseFail.Snapshot().Count()) + require.EqualValues(t, 0, stats.addressedCallSignatureValidationFail.Snapshot().Count()) + require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) + }, + }, + "unknown message": { + setup: func(_ Backend) (request []byte, expectedResponse []byte) { + unknownPayload, err := payload.NewAddressedCall([]byte{0, 0, 0}, []byte("unknown message")) + require.NoError(t, err) + unknownMessage, err := avalancheWarp.NewUnsignedMessage(snowCtx.NetworkID, snowCtx.ChainID, unknownPayload.Bytes()) + require.NoError(t, err) + return unknownMessage.Bytes(), nil + }, + verifyStats: func(t *testing.T, stats *verifierStats) { + require.EqualValues(t, 0, stats.messageParseFail.Snapshot().Count()) + require.EqualValues(t, 1, stats.addressedCallSignatureValidationFail.Snapshot().Count()) + require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) + }, + err: &common.AppError{Code: ParseErrCode}, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + sigCache := &cache.LRU[ids.ID, []byte]{Size: 100} + warpBackend, err := NewBackend(snowCtx.NetworkID, snowCtx.ChainID, warpSigner, warptest.EmptyBlockClient, database, sigCache, [][]byte{offchainMessage.Bytes()}) + require.NoError(t, err) + handler := acp118.NewCachedHandler(sigCache, warpBackend, warpSigner) + + requestBytes, expectedResponse := test.setup(warpBackend) + protoMsg := &sdk.SignatureRequest{Message: requestBytes} + protoBytes, err := proto.Marshal(protoMsg) + require.NoError(t, err) + responseBytes, appErr := handler.AppRequest(context.Background(), ids.GenerateTestNodeID(), time.Time{}, protoBytes) + if test.err != nil { + require.Error(t, appErr) + require.ErrorIs(t, appErr, test.err) + } else { + require.Nil(t, appErr) + } + + test.verifyStats(t, warpBackend.(*backend).stats) + + // If the expected response is empty, assert that the handler returns an empty response and return early. + if len(expectedResponse) == 0 { + require.Len(t, responseBytes, 0, "expected response to be empty") + return + } + response := &sdk.SignatureResponse{} + require.NoError(t, proto.Unmarshal(responseBytes, response)) + require.NoError(t, err, "error unmarshalling SignatureResponse") + + require.Equal(t, expectedResponse, response.Signature) + }) + } +} + +func TestBlockSignatures(t *testing.T) { + database := memdb.New() + snowCtx := utils.TestSnowContext() + blsSecretKey, err := bls.NewSecretKey() + require.NoError(t, err) + + warpSigner := avalancheWarp.NewSigner(blsSecretKey, snowCtx.NetworkID, snowCtx.ChainID) + blkID := ids.GenerateTestID() + blockClient := warptest.MakeBlockClient(blkID) + + unknownBlockID := ids.GenerateTestID() + + toMessageBytes := func(id ids.ID) []byte { + idPayload, err := payload.NewHash(id) + require.NoError(t, err) + + msg, err := avalancheWarp.NewUnsignedMessage(snowCtx.NetworkID, snowCtx.ChainID, idPayload.Bytes()) + require.NoError(t, err) + + return msg.Bytes() + } + + tests := map[string]struct { + setup func() (request []byte, expectedResponse []byte) + verifyStats func(t *testing.T, stats *verifierStats) + err error + }{ + "known block": { + setup: func() (request []byte, expectedResponse []byte) { + hashPayload, err := payload.NewHash(blkID) + require.NoError(t, err) + unsignedMessage, err := avalancheWarp.NewUnsignedMessage(snowCtx.NetworkID, snowCtx.ChainID, hashPayload.Bytes()) + require.NoError(t, err) + signature, err := warpSigner.Sign(unsignedMessage) + require.NoError(t, err) + return toMessageBytes(blkID), signature[:] + }, + verifyStats: func(t *testing.T, stats *verifierStats) { + require.EqualValues(t, 0, stats.addressedCallSignatureValidationFail.Snapshot().Count()) + require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) + require.EqualValues(t, 0, stats.messageParseFail.Snapshot().Count()) + }, + }, + "unknown block": { + setup: func() (request []byte, expectedResponse []byte) { + return toMessageBytes(unknownBlockID), nil + }, + verifyStats: func(t *testing.T, stats *verifierStats) { + require.EqualValues(t, 0, stats.addressedCallSignatureValidationFail.Snapshot().Count()) + require.EqualValues(t, 1, stats.blockSignatureValidationFail.Snapshot().Count()) + require.EqualValues(t, 0, stats.messageParseFail.Snapshot().Count()) + }, + err: &common.AppError{Code: VerifyErrCode}, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + sigCache := &cache.LRU[ids.ID, []byte]{Size: 100} + warpBackend, err := NewBackend( + snowCtx.NetworkID, + snowCtx.ChainID, + warpSigner, + blockClient, + database, + sigCache, + nil, + ) + require.NoError(t, err) + handler := acp118.NewCachedHandler(sigCache, warpBackend, warpSigner) + + requestBytes, expectedResponse := test.setup() + protoMsg := &sdk.SignatureRequest{Message: requestBytes} + protoBytes, err := proto.Marshal(protoMsg) + require.NoError(t, err) + responseBytes, appErr := handler.AppRequest(context.Background(), ids.GenerateTestNodeID(), time.Time{}, protoBytes) + if test.err != nil { + require.NotNil(t, appErr) + require.ErrorIs(t, test.err, appErr) + } else { + require.Nil(t, appErr) + } + + test.verifyStats(t, warpBackend.(*backend).stats) + + // If the expected response is empty, assert that the handler returns an empty response and return early. + if len(expectedResponse) == 0 { + require.Len(t, responseBytes, 0, "expected response to be empty") + return + } + var response sdk.SignatureResponse + err = proto.Unmarshal(responseBytes, &response) + require.NoError(t, err, "error unmarshalling SignatureResponse") + + require.Equal(t, expectedResponse, response.Signature) + }) + } +} diff --git a/warp/wrapped_cache.go b/warp/wrapped_cache.go new file mode 100644 index 0000000000..8d70ac50b2 --- /dev/null +++ b/warp/wrapped_cache.go @@ -0,0 +1,52 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package warp + +import ( + "github.com/ava-labs/avalanchego/cache" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/proto/pb/sdk" + "github.com/ethereum/go-ethereum/log" + "google.golang.org/protobuf/proto" +) + +type wrappedCache struct { + cache.Cacher[ids.ID, []byte] +} + +// NewWrappedCache takes a SDK cache that caches SignatureResponses and wraps it +// to return the Signature from the SignatureResponse. +func NewWrappedCache(sdkCache cache.Cacher[ids.ID, []byte]) cache.Cacher[ids.ID, []byte] { + return &wrappedCache{ + Cacher: sdkCache, + } +} + +func (w *wrappedCache) Get(key ids.ID) ([]byte, bool) { + responseBytes, ok := w.Cacher.Get(key) + if !ok { + return responseBytes, false + } + response := sdk.SignatureResponse{} + err := proto.Unmarshal(responseBytes, &response) + if err != nil { + log.Error("failed to unmarshal cached SignatureResponse", "error", err) + return nil, false + } + + return response.Signature, true +} + +func (w *wrappedCache) Put(key ids.ID, value []byte) { + response := sdk.SignatureResponse{ + Signature: value, + } + responseBytes, err := proto.Marshal(&response) + if err != nil { + log.Error("failed to marshal SignatureResponse", "error", err) + return + } + + w.Cacher.Put(key, responseBytes) +} From 8851256206d1a63df21fd0d017429daaead8d5fb Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Sun, 13 Oct 2024 14:12:51 +0300 Subject: [PATCH 15/23] prune warp db before backend init --- plugin/evm/vm.go | 14 ++++----- plugin/evm/vm_warp_test.go | 59 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 02a9420211..977eb2e23b 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -494,6 +494,13 @@ func (vm *VM) Initialize( return fmt.Errorf("failed to create warp signature cache: %w", err) } + // clear warpdb on initialization if config enabled + if vm.config.PruneWarpDB { + if err := database.Clear(vm.warpDB, ethdb.IdealBatchSize); err != nil { + return fmt.Errorf("failed to prune warpDB: %w", err) + } + } + vm.warpBackend, err = warp.NewBackend( vm.ctx.NetworkID, vm.ctx.ChainID, @@ -507,13 +514,6 @@ func (vm *VM) Initialize( return err } - // clear warpdb on initialization if config enabled - if vm.config.PruneWarpDB { - if err := database.Clear(vm.warpDB, ethdb.IdealBatchSize); err != nil { - return fmt.Errorf("failed to prune warpDB: %w", err) - } - } - if err := vm.initializeChain(lastAcceptedHash, vm.ethConfig); err != nil { return err } diff --git a/plugin/evm/vm_warp_test.go b/plugin/evm/vm_warp_test.go index 0297f6df62..f0b136df22 100644 --- a/plugin/evm/vm_warp_test.go +++ b/plugin/evm/vm_warp_test.go @@ -14,6 +14,7 @@ import ( "github.com/ava-labs/avalanchego/ids" commonEng "github.com/ava-labs/avalanchego/snow/engine/common" + "github.com/ava-labs/avalanchego/snow/engine/enginetest" "github.com/ava-labs/avalanchego/snow/engine/snowman/block" "github.com/ava-labs/avalanchego/snow/validators" "github.com/ava-labs/avalanchego/snow/validators/validatorstest" @@ -35,6 +36,7 @@ import ( "github.com/ava-labs/subnet-evm/precompile/contracts/warp" "github.com/ava-labs/subnet-evm/predicate" "github.com/ava-labs/subnet-evm/utils" + corewarp "github.com/ava-labs/subnet-evm/warp" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" @@ -853,3 +855,60 @@ func TestBlockSignatureRequestsToVM(t *testing.T) { }) } } + +func TestClearWarpDB(t *testing.T) { + ctx, db, genesisBytes, issuer, _ := setupGenesis(t, genesisJSONLatest) + vm := &VM{} + err := vm.Initialize(context.Background(), ctx, db, genesisBytes, []byte{}, []byte{}, issuer, []*commonEng.Fx{}, &enginetest.Sender{}) + require.NoError(t, err) + + // use multiple messages to test that all messages get cleared + payloads := [][]byte{[]byte("test1"), []byte("test2"), []byte("test3"), []byte("test4"), []byte("test5")} + messages := []*avalancheWarp.UnsignedMessage{} + + // add all messages + for _, payload := range payloads { + unsignedMsg, err := avalancheWarp.NewUnsignedMessage(vm.ctx.NetworkID, vm.ctx.ChainID, payload) + require.NoError(t, err) + err = vm.warpBackend.AddMessage(unsignedMsg) + require.NoError(t, err) + // ensure that the message was added + _, err = vm.warpBackend.GetMessageSignature(unsignedMsg) + require.NoError(t, err) + messages = append(messages, unsignedMsg) + } + + require.NoError(t, vm.Shutdown(context.Background())) + + // Restart VM with the same database default should not prune the warp db + vm = &VM{} + ctx, _, _, _, _ = setupGenesis(t, genesisJSONLatest) + err = vm.Initialize(context.Background(), ctx, db, genesisBytes, []byte{}, []byte{}, issuer, []*commonEng.Fx{}, &enginetest.Sender{}) + require.NoError(t, err) + + // check messages are still present + for _, message := range messages { + bytes, err := vm.warpBackend.GetMessageSignature(message) + require.NoError(t, err) + require.NotEmpty(t, bytes) + } + + require.NoError(t, vm.Shutdown(context.Background())) + + // restart the VM with pruning enabled + vm = &VM{} + config := `{"prune-warp-db-enabled": true}` + ctx, _, _, _, _ = setupGenesis(t, genesisJSONLatest) + err = vm.Initialize(context.Background(), ctx, db, genesisBytes, []byte{}, []byte(config), issuer, []*commonEng.Fx{}, &enginetest.Sender{}) + require.NoError(t, err) + + it := vm.warpDB.NewIterator() + require.False(t, it.Next()) + it.Release() + + // ensure all messages have been deleted + for _, message := range messages { + _, err := vm.warpBackend.GetMessageSignature(message) + require.ErrorIs(t, err, &commonEng.AppError{Code: corewarp.ParseErrCode}) + } +} From 1a75f6c10c891b70c2ca1086cc8dbc03661701ac Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Mon, 14 Oct 2024 14:06:00 +0300 Subject: [PATCH 16/23] add cache tests --- warp/verifier_backend_test.go | 155 +++++++++++++++++++++------------- 1 file changed, 95 insertions(+), 60 deletions(-) diff --git a/warp/verifier_backend_test.go b/warp/verifier_backend_test.go index 6b0c120db6..79d63ce383 100644 --- a/warp/verifier_backend_test.go +++ b/warp/verifier_backend_test.go @@ -88,37 +88,55 @@ func TestAddressedCallSignatures(t *testing.T) { } for name, test := range tests { - t.Run(name, func(t *testing.T) { - sigCache := &cache.LRU[ids.ID, []byte]{Size: 100} - warpBackend, err := NewBackend(snowCtx.NetworkID, snowCtx.ChainID, warpSigner, warptest.EmptyBlockClient, database, sigCache, [][]byte{offchainMessage.Bytes()}) - require.NoError(t, err) - handler := acp118.NewCachedHandler(sigCache, warpBackend, warpSigner) - - requestBytes, expectedResponse := test.setup(warpBackend) - protoMsg := &sdk.SignatureRequest{Message: requestBytes} - protoBytes, err := proto.Marshal(protoMsg) - require.NoError(t, err) - responseBytes, appErr := handler.AppRequest(context.Background(), ids.GenerateTestNodeID(), time.Time{}, protoBytes) - if test.err != nil { - require.Error(t, appErr) - require.ErrorIs(t, appErr, test.err) + for _, withCache := range []bool{true, false} { + if withCache { + name += "_with_cache" } else { - require.Nil(t, appErr) + name += "_no_cache" } + t.Run(name, func(t *testing.T) { + var sigCache cache.Cacher[ids.ID, []byte] + if withCache { + sigCache = &cache.LRU[ids.ID, []byte]{Size: 100} + } else { + sigCache = &cache.Empty[ids.ID, []byte]{} + } + warpBackend, err := NewBackend(snowCtx.NetworkID, snowCtx.ChainID, warpSigner, warptest.EmptyBlockClient, database, sigCache, [][]byte{offchainMessage.Bytes()}) + require.NoError(t, err) + handler := acp118.NewCachedHandler(sigCache, warpBackend, warpSigner) + + requestBytes, expectedResponse := test.setup(warpBackend) + protoMsg := &sdk.SignatureRequest{Message: requestBytes} + protoBytes, err := proto.Marshal(protoMsg) + require.NoError(t, err) + responseBytes, appErr := handler.AppRequest(context.Background(), ids.GenerateTestNodeID(), time.Time{}, protoBytes) + if test.err != nil { + require.Error(t, appErr) + require.ErrorIs(t, appErr, test.err) + } else { + require.Nil(t, appErr) + } - test.verifyStats(t, warpBackend.(*backend).stats) + test.verifyStats(t, warpBackend.(*backend).stats) - // If the expected response is empty, assert that the handler returns an empty response and return early. - if len(expectedResponse) == 0 { - require.Len(t, responseBytes, 0, "expected response to be empty") - return - } - response := &sdk.SignatureResponse{} - require.NoError(t, proto.Unmarshal(responseBytes, response)) - require.NoError(t, err, "error unmarshalling SignatureResponse") + // If the expected response is empty, assert that the handler returns an empty response and return early. + if len(expectedResponse) == 0 { + require.Len(t, responseBytes, 0, "expected response to be empty") + return + } + // check cache is populated + if withCache { + require.NotZero(t, warpBackend.(*backend).signatureCache.Len()) + } else { + require.Zero(t, warpBackend.(*backend).signatureCache.Len()) + } + response := &sdk.SignatureResponse{} + require.NoError(t, proto.Unmarshal(responseBytes, response)) + require.NoError(t, err, "error unmarshalling SignatureResponse") - require.Equal(t, expectedResponse, response.Signature) - }) + require.Equal(t, expectedResponse, response.Signature) + }) + } } } @@ -179,44 +197,61 @@ func TestBlockSignatures(t *testing.T) { } for name, test := range tests { - t.Run(name, func(t *testing.T) { - sigCache := &cache.LRU[ids.ID, []byte]{Size: 100} - warpBackend, err := NewBackend( - snowCtx.NetworkID, - snowCtx.ChainID, - warpSigner, - blockClient, - database, - sigCache, - nil, - ) - require.NoError(t, err) - handler := acp118.NewCachedHandler(sigCache, warpBackend, warpSigner) - - requestBytes, expectedResponse := test.setup() - protoMsg := &sdk.SignatureRequest{Message: requestBytes} - protoBytes, err := proto.Marshal(protoMsg) - require.NoError(t, err) - responseBytes, appErr := handler.AppRequest(context.Background(), ids.GenerateTestNodeID(), time.Time{}, protoBytes) - if test.err != nil { - require.NotNil(t, appErr) - require.ErrorIs(t, test.err, appErr) + for _, withCache := range []bool{true, false} { + if withCache { + name += "_with_cache" } else { - require.Nil(t, appErr) + name += "_no_cache" } + t.Run(name, func(t *testing.T) { + var sigCache cache.Cacher[ids.ID, []byte] + if withCache { + sigCache = &cache.LRU[ids.ID, []byte]{Size: 100} + } else { + sigCache = &cache.Empty[ids.ID, []byte]{} + } + warpBackend, err := NewBackend( + snowCtx.NetworkID, + snowCtx.ChainID, + warpSigner, + blockClient, + database, + sigCache, + nil, + ) + require.NoError(t, err) + handler := acp118.NewCachedHandler(sigCache, warpBackend, warpSigner) - test.verifyStats(t, warpBackend.(*backend).stats) + requestBytes, expectedResponse := test.setup() + protoMsg := &sdk.SignatureRequest{Message: requestBytes} + protoBytes, err := proto.Marshal(protoMsg) + require.NoError(t, err) + responseBytes, appErr := handler.AppRequest(context.Background(), ids.GenerateTestNodeID(), time.Time{}, protoBytes) + if test.err != nil { + require.NotNil(t, appErr) + require.ErrorIs(t, test.err, appErr) + } else { + require.Nil(t, appErr) + } - // If the expected response is empty, assert that the handler returns an empty response and return early. - if len(expectedResponse) == 0 { - require.Len(t, responseBytes, 0, "expected response to be empty") - return - } - var response sdk.SignatureResponse - err = proto.Unmarshal(responseBytes, &response) - require.NoError(t, err, "error unmarshalling SignatureResponse") + test.verifyStats(t, warpBackend.(*backend).stats) - require.Equal(t, expectedResponse, response.Signature) - }) + // If the expected response is empty, assert that the handler returns an empty response and return early. + if len(expectedResponse) == 0 { + require.Len(t, responseBytes, 0, "expected response to be empty") + return + } + // check cache is populated + if withCache { + require.NotZero(t, warpBackend.(*backend).signatureCache.Len()) + } else { + require.Zero(t, warpBackend.(*backend).signatureCache.Len()) + } + var response sdk.SignatureResponse + err = proto.Unmarshal(responseBytes, &response) + require.NoError(t, err, "error unmarshalling SignatureResponse") + require.Equal(t, expectedResponse, response.Signature) + }) + } } } From 7143fc5e068f75fbcc67e6d393c77cf76159386e Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Mon, 14 Oct 2024 14:08:47 +0300 Subject: [PATCH 17/23] remove uptime msg type --- warp/messages/codec.go | 1 - warp/messages/validator_uptime.go | 51 ------------------------------- 2 files changed, 52 deletions(-) delete mode 100644 warp/messages/validator_uptime.go diff --git a/warp/messages/codec.go b/warp/messages/codec.go index 87d2fa334a..ac736cbf67 100644 --- a/warp/messages/codec.go +++ b/warp/messages/codec.go @@ -24,7 +24,6 @@ func init() { lc := linearcodec.NewDefault() err := errors.Join( - lc.RegisterType(&ValidatorUptime{}), Codec.RegisterCodec(CodecVersion, lc), ) if err != nil { diff --git a/warp/messages/validator_uptime.go b/warp/messages/validator_uptime.go deleted file mode 100644 index 3d3e4dd5dd..0000000000 --- a/warp/messages/validator_uptime.go +++ /dev/null @@ -1,51 +0,0 @@ -// (c) 2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package messages - -import ( - "fmt" - - "github.com/ava-labs/avalanchego/ids" -) - -// ValidatorUptime is signed when the ValidationID is known and the validator -// has been up for TotalUptime seconds. -type ValidatorUptime struct { - ValidationID ids.ID `serialize:"true"` - TotalUptime uint64 `serialize:"true"` - - bytes []byte -} - -// NewValidatorUptime creates a new *ValidatorUptime and initializes it. -func NewValidatorUptime(validationID ids.ID, totalUptime uint64) (*ValidatorUptime, error) { - bhp := &ValidatorUptime{ - ValidationID: validationID, - TotalUptime: totalUptime, - } - return bhp, initialize(bhp) -} - -// ParseValidatorUptime converts a slice of bytes into an initialized ValidatorUptime. -func ParseValidatorUptime(b []byte) (*ValidatorUptime, error) { - payloadIntf, err := Parse(b) - if err != nil { - return nil, err - } - payload, ok := payloadIntf.(*ValidatorUptime) - if !ok { - return nil, fmt.Errorf("%w: %T", errWrongType, payloadIntf) - } - return payload, nil -} - -// Bytes returns the binary representation of this payload. It assumes that the -// payload is initialized from either NewValidatorUptime or Parse. -func (b *ValidatorUptime) Bytes() []byte { - return b.bytes -} - -func (b *ValidatorUptime) initialize(bytes []byte) { - b.bytes = bytes -} From 243fe5feb5b893412133d3090d823e3ee8455d44 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Mon, 14 Oct 2024 14:09:01 +0300 Subject: [PATCH 18/23] add cache test --- warp/verifier_backend.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/warp/verifier_backend.go b/warp/verifier_backend.go index 64249bbba6..d5572071db 100644 --- a/warp/verifier_backend.go +++ b/warp/verifier_backend.go @@ -94,8 +94,6 @@ func (b *backend) verifyAddressedCall(addressedCall *payload.AddressedCall) *com } switch p := parsed.(type) { - case *messages.ValidatorUptime: - return nil default: return &common.AppError{ Code: ParseErrCode, From 02eb89bb3651c42ad6a976dc6bdf5a704ea27ec6 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Mon, 14 Oct 2024 14:37:23 +0300 Subject: [PATCH 19/23] fix linter --- warp/messages/payload.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/warp/messages/payload.go b/warp/messages/payload.go index facf54524d..bea796f1dd 100644 --- a/warp/messages/payload.go +++ b/warp/messages/payload.go @@ -3,13 +3,6 @@ package messages -import ( - "errors" - "fmt" -) - -var errWrongType = errors.New("wrong payload type") - // Payload provides a common interface for all payloads implemented by this // package. type Payload interface { @@ -28,12 +21,3 @@ func Parse(bytes []byte) (Payload, error) { payload.initialize(bytes) return payload, nil } - -func initialize(p Payload) error { - bytes, err := Codec.Marshal(CodecVersion, &p) - if err != nil { - return fmt.Errorf("couldn't marshal %T payload: %w", p, err) - } - p.initialize(bytes) - return nil -} From aced0034d51805e5f53131ba66221248b386d152 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Mon, 14 Oct 2024 15:53:19 +0300 Subject: [PATCH 20/23] add validator uptimes --- warp/messages/codec.go | 1 + warp/messages/payload.go | 22 +++++++++++++ warp/messages/validator_uptime.go | 51 +++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 warp/messages/validator_uptime.go diff --git a/warp/messages/codec.go b/warp/messages/codec.go index ac736cbf67..87d2fa334a 100644 --- a/warp/messages/codec.go +++ b/warp/messages/codec.go @@ -24,6 +24,7 @@ func init() { lc := linearcodec.NewDefault() err := errors.Join( + lc.RegisterType(&ValidatorUptime{}), Codec.RegisterCodec(CodecVersion, lc), ) if err != nil { diff --git a/warp/messages/payload.go b/warp/messages/payload.go index bea796f1dd..3776a1356d 100644 --- a/warp/messages/payload.go +++ b/warp/messages/payload.go @@ -3,6 +3,13 @@ package messages +import ( + "errors" + "fmt" +) + +var errWrongType = errors.New("wrong payload type") + // Payload provides a common interface for all payloads implemented by this // package. type Payload interface { @@ -13,6 +20,12 @@ type Payload interface { initialize(b []byte) } +// Signable is an optional interface that payloads can implement to allow +// on-the-fly signing of incoming messages by the warp backend. +type Signable interface { + VerifyMesssage(sourceAddress []byte) error +} + func Parse(bytes []byte) (Payload, error) { var payload Payload if _, err := Codec.Unmarshal(bytes, &payload); err != nil { @@ -21,3 +34,12 @@ func Parse(bytes []byte) (Payload, error) { payload.initialize(bytes) return payload, nil } + +func initialize(p Payload) error { + bytes, err := Codec.Marshal(CodecVersion, &p) + if err != nil { + return fmt.Errorf("couldn't marshal %T payload: %w", p, err) + } + p.initialize(bytes) + return nil +} diff --git a/warp/messages/validator_uptime.go b/warp/messages/validator_uptime.go new file mode 100644 index 0000000000..3d3e4dd5dd --- /dev/null +++ b/warp/messages/validator_uptime.go @@ -0,0 +1,51 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package messages + +import ( + "fmt" + + "github.com/ava-labs/avalanchego/ids" +) + +// ValidatorUptime is signed when the ValidationID is known and the validator +// has been up for TotalUptime seconds. +type ValidatorUptime struct { + ValidationID ids.ID `serialize:"true"` + TotalUptime uint64 `serialize:"true"` + + bytes []byte +} + +// NewValidatorUptime creates a new *ValidatorUptime and initializes it. +func NewValidatorUptime(validationID ids.ID, totalUptime uint64) (*ValidatorUptime, error) { + bhp := &ValidatorUptime{ + ValidationID: validationID, + TotalUptime: totalUptime, + } + return bhp, initialize(bhp) +} + +// ParseValidatorUptime converts a slice of bytes into an initialized ValidatorUptime. +func ParseValidatorUptime(b []byte) (*ValidatorUptime, error) { + payloadIntf, err := Parse(b) + if err != nil { + return nil, err + } + payload, ok := payloadIntf.(*ValidatorUptime) + if !ok { + return nil, fmt.Errorf("%w: %T", errWrongType, payloadIntf) + } + return payload, nil +} + +// Bytes returns the binary representation of this payload. It assumes that the +// payload is initialized from either NewValidatorUptime or Parse. +func (b *ValidatorUptime) Bytes() []byte { + return b.bytes +} + +func (b *ValidatorUptime) initialize(bytes []byte) { + b.bytes = bytes +} From 1b69139c0c7b8d5ad25d7862ad2c7f0f3569a3f6 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Fri, 18 Oct 2024 15:21:35 +0300 Subject: [PATCH 21/23] use signature cache --- go.mod | 28 +++++++++---------- go.sum | 65 ++++++++++++++++++++----------------------- warp/backend.go | 4 +-- warp/wrapped_cache.go | 52 ---------------------------------- 4 files changed, 46 insertions(+), 103 deletions(-) delete mode 100644 warp/wrapped_cache.go diff --git a/go.mod b/go.mod index e11faaf417..13ee1a2861 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22.8 require ( github.com/VictoriaMetrics/fastcache v1.12.1 github.com/antithesishq/antithesis-sdk-go v0.3.8 - github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241009195818-ab58a805404b + github.com/ava-labs/avalanchego v1.11.13-0.20241018024240-22fb2f016633 github.com/cespare/cp v0.1.0 github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 github.com/davecgh/go-spew v1.1.1 @@ -37,16 +37,16 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.12.0 github.com/status-im/keycard-go v0.2.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 github.com/tyler-smith/go-bip39 v1.1.0 github.com/urfave/cli/v2 v2.25.7 go.uber.org/goleak v1.3.0 go.uber.org/mock v0.4.0 - golang.org/x/crypto v0.22.0 + golang.org/x/crypto v0.26.0 golang.org/x/exp v0.0.0-20231127185646-65229373498e - golang.org/x/sync v0.7.0 - golang.org/x/sys v0.19.0 - golang.org/x/text v0.14.0 + golang.org/x/sync v0.8.0 + golang.org/x/sys v0.24.0 + golang.org/x/text v0.17.0 golang.org/x/time v0.3.0 google.golang.org/protobuf v1.34.2 gopkg.in/natefinch/lumberjack.v2 v2.0.0 @@ -61,7 +61,7 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 // indirect @@ -118,7 +118,7 @@ require ( github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect - github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rs/cors v1.7.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect @@ -141,13 +141,13 @@ require ( go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/term v0.19.0 // indirect - golang.org/x/tools v0.20.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/term v0.23.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gonum.org/v1/gonum v0.11.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect - google.golang.org/grpc v1.62.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect + google.golang.org/grpc v1.66.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index a2d380588b..d9c6e9d4cb 100644 --- a/go.sum +++ b/go.sum @@ -58,12 +58,8 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax github.com/antithesishq/antithesis-sdk-go v0.3.8 h1:OvGoHxIcOXFJLyn9IJQ5DzByZ3YVAWNBc394ObzDRb8= github.com/antithesishq/antithesis-sdk-go v0.3.8/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241004185122-5285749cc752 h1:pQh5HA1sf31baNmN6RZpI02JOLmv7o7TcBY4VpuOSMI= -github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241004185122-5285749cc752/go.mod h1:qSHmog3wMVjo/ruIAQo0ppXAilyni07NIu5K88RyhWE= -github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241009154434-5d66c421bf61 h1:Emh/obJT0CU4rfS4dkLOFqcHuM66yHFkRynUzFUCX0Q= -github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241009154434-5d66c421bf61/go.mod h1:qSHmog3wMVjo/ruIAQo0ppXAilyni07NIu5K88RyhWE= -github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241009195818-ab58a805404b h1:gYej1NcDzOMGi03rgO0g8UiJVV/eCG33iVqs3HhDw4Y= -github.com/ava-labs/avalanchego v1.11.12-rc.2.0.20241009195818-ab58a805404b/go.mod h1:qSHmog3wMVjo/ruIAQo0ppXAilyni07NIu5K88RyhWE= +github.com/ava-labs/avalanchego v1.11.13-0.20241018024240-22fb2f016633 h1:SD2ubEZZ7/C1/4ivDDuzT1WKNKzZalf3SNAzY7+u4lw= +github.com/ava-labs/avalanchego v1.11.13-0.20241018024240-22fb2f016633/go.mod h1:YlinMYWE4yXu4bA5Vdzn1WcQ+z5qjrpxeBYwWAPdrvA= github.com/ava-labs/coreth v0.13.8 h1:f14X3KgwHl9LwzfxlN6S4bbn5VA2rhEsNnHaRLSTo/8= github.com/ava-labs/coreth v0.13.8/go.mod h1:t3BSv/eQv0AlDPMfEDCMMoD/jq1RkUsbFzQAFg5qBcE= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= @@ -100,8 +96,9 @@ github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -245,8 +242,8 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= -github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= +github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -512,8 +509,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -560,8 +557,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= @@ -650,8 +647,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -734,8 +731,8 @@ golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -757,8 +754,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -826,12 +823,12 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -842,8 +839,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -905,8 +902,8 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= -golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -978,12 +975,10 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= -google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= -google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 h1:Lj5rbfG876hIAYFjqiJnPHfhXbv+nzTWfm04Fg/XSVU= -google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= +google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU= +google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed h1:J6izYgfBXAI3xTKLgxzTmUltdYaLsuBxFCgDHWJ/eXg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -1002,8 +997,8 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= +google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/warp/backend.go b/warp/backend.go index 8d60fee41e..fb95cb02e1 100644 --- a/warp/backend.go +++ b/warp/backend.go @@ -69,7 +69,7 @@ func NewBackend( warpSigner avalancheWarp.Signer, blockClient BlockClient, db database.Database, - sdkCache cache.Cacher[ids.ID, []byte], + signatureCache cache.Cacher[ids.ID, []byte], offchainMessages [][]byte, ) (Backend, error) { b := &backend{ @@ -80,7 +80,7 @@ func NewBackend( blockClient: blockClient, // sdkCache returns sdk.SignatureResponse proto bytes, // and it must be wrapped to return Signature bytes. - signatureCache: NewWrappedCache(sdkCache), + signatureCache: signatureCache, messageCache: &cache.LRU[ids.ID, *avalancheWarp.UnsignedMessage]{Size: messageCacheSize}, stats: newVerifierStats(), offchainAddressedCallMsgs: make(map[ids.ID]*avalancheWarp.UnsignedMessage), diff --git a/warp/wrapped_cache.go b/warp/wrapped_cache.go deleted file mode 100644 index 8d70ac50b2..0000000000 --- a/warp/wrapped_cache.go +++ /dev/null @@ -1,52 +0,0 @@ -// (c) 2023, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package warp - -import ( - "github.com/ava-labs/avalanchego/cache" - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/proto/pb/sdk" - "github.com/ethereum/go-ethereum/log" - "google.golang.org/protobuf/proto" -) - -type wrappedCache struct { - cache.Cacher[ids.ID, []byte] -} - -// NewWrappedCache takes a SDK cache that caches SignatureResponses and wraps it -// to return the Signature from the SignatureResponse. -func NewWrappedCache(sdkCache cache.Cacher[ids.ID, []byte]) cache.Cacher[ids.ID, []byte] { - return &wrappedCache{ - Cacher: sdkCache, - } -} - -func (w *wrappedCache) Get(key ids.ID) ([]byte, bool) { - responseBytes, ok := w.Cacher.Get(key) - if !ok { - return responseBytes, false - } - response := sdk.SignatureResponse{} - err := proto.Unmarshal(responseBytes, &response) - if err != nil { - log.Error("failed to unmarshal cached SignatureResponse", "error", err) - return nil, false - } - - return response.Signature, true -} - -func (w *wrappedCache) Put(key ids.ID, value []byte) { - response := sdk.SignatureResponse{ - Signature: value, - } - responseBytes, err := proto.Marshal(&response) - if err != nil { - log.Error("failed to marshal SignatureResponse", "error", err) - return - } - - w.Cacher.Put(key, responseBytes) -} From 0ac4c72c67e0252c1c97d8d7c10689460e49a3ef Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Fri, 18 Oct 2024 15:32:29 +0300 Subject: [PATCH 22/23] bump avago version --- scripts/versions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/versions.sh b/scripts/versions.sh index d5783f2838..e8ade44aeb 100644 --- a/scripts/versions.sh +++ b/scripts/versions.sh @@ -4,7 +4,7 @@ # shellcheck disable=SC2034 # Don't export them as they're used in the context of other calls -AVALANCHE_VERSION=${AVALANCHE_VERSION:-'43d5b435'} +AVALANCHE_VERSION=${AVALANCHE_VERSION:-'22fb2f01'} GINKGO_VERSION=${GINKGO_VERSION:-'v2.2.0'} # This won't be used, but it's here to make code syncs easier From 7f71052ca337b867f8a0161d906391abeb695d6d Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Fri, 18 Oct 2024 16:22:29 +0300 Subject: [PATCH 23/23] nits --- warp/backend.go | 12 +++++------- warp/backend_test.go | 4 ++-- warp/verifier_backend.go | 5 +++-- warp/verifier_backend_test.go | 4 ++-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/warp/backend.go b/warp/backend.go index fb95cb02e1..25cee0d361 100644 --- a/warp/backend.go +++ b/warp/backend.go @@ -73,13 +73,11 @@ func NewBackend( offchainMessages [][]byte, ) (Backend, error) { b := &backend{ - networkID: networkID, - sourceChainID: sourceChainID, - db: db, - warpSigner: warpSigner, - blockClient: blockClient, - // sdkCache returns sdk.SignatureResponse proto bytes, - // and it must be wrapped to return Signature bytes. + networkID: networkID, + sourceChainID: sourceChainID, + db: db, + warpSigner: warpSigner, + blockClient: blockClient, signatureCache: signatureCache, messageCache: &cache.LRU[ids.ID, *avalancheWarp.UnsignedMessage]{Size: messageCacheSize}, stats: newVerifierStats(), diff --git a/warp/backend_test.go b/warp/backend_test.go index 91129bd104..cefc0d13cc 100644 --- a/warp/backend_test.go +++ b/warp/backend_test.go @@ -84,7 +84,7 @@ func TestGetBlockSignature(t *testing.T) { sk, err := bls.NewSecretKey() require.NoError(err) warpSigner := avalancheWarp.NewSigner(sk, networkID, sourceChainID) - messageSignatureCache := &cache.LRU[ids.ID, []byte]{} + messageSignatureCache := &cache.LRU[ids.ID, []byte]{Size: 500} backend, err := NewBackend(networkID, sourceChainID, warpSigner, blockClient, db, messageSignatureCache, nil) require.NoError(err) @@ -165,7 +165,7 @@ func TestOffChainMessages(t *testing.T) { require := require.New(t) db := memdb.New() - messageSignatureCache := &cache.LRU[ids.ID, []byte]{Size: 500} + messageSignatureCache := &cache.LRU[ids.ID, []byte]{Size: 0} backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, db, messageSignatureCache, test.offchainMessages) require.ErrorIs(err, test.err) if test.check != nil { diff --git a/warp/verifier_backend.go b/warp/verifier_backend.go index d5572071db..861dc2d22f 100644 --- a/warp/verifier_backend.go +++ b/warp/verifier_backend.go @@ -49,13 +49,11 @@ func (b *backend) verifyMessage(unsignedMessage *avalancheWarp.UnsignedMessage) case *payload.AddressedCall: apperr := b.verifyAddressedCall(p) if apperr != nil { - b.stats.IncAddressedCallSignatureValidationFail() return apperr } case *payload.Hash: apperr := b.verifyBlockMessage(p) if apperr != nil { - b.stats.IncBlockSignatureValidationFail() return apperr } default: @@ -73,6 +71,7 @@ func (b *backend) verifyBlockMessage(blockHashPayload *payload.Hash) *common.App blockID := blockHashPayload.Hash _, err := b.blockClient.GetAcceptedBlock(context.TODO(), blockID) if err != nil { + b.stats.IncBlockSignatureValidationFail() return &common.AppError{ Code: VerifyErrCode, Message: fmt.Sprintf("failed to get block %s: %s", blockID, err.Error()), @@ -87,6 +86,7 @@ func (b *backend) verifyAddressedCall(addressedCall *payload.AddressedCall) *com // Further, parse the payload to see if it is a known type. parsed, err := messages.Parse(addressedCall.Payload) if err != nil { + b.stats.IncMessageParseFail() return &common.AppError{ Code: ParseErrCode, Message: "failed to parse addressed call message: " + err.Error(), @@ -95,6 +95,7 @@ func (b *backend) verifyAddressedCall(addressedCall *payload.AddressedCall) *com switch p := parsed.(type) { default: + b.stats.IncMessageParseFail() return &common.AppError{ Code: ParseErrCode, Message: fmt.Sprintf("unknown message type: %T", p), diff --git a/warp/verifier_backend_test.go b/warp/verifier_backend_test.go index 79d63ce383..22ca29e792 100644 --- a/warp/verifier_backend_test.go +++ b/warp/verifier_backend_test.go @@ -79,8 +79,8 @@ func TestAddressedCallSignatures(t *testing.T) { return unknownMessage.Bytes(), nil }, verifyStats: func(t *testing.T, stats *verifierStats) { - require.EqualValues(t, 0, stats.messageParseFail.Snapshot().Count()) - require.EqualValues(t, 1, stats.addressedCallSignatureValidationFail.Snapshot().Count()) + require.EqualValues(t, 1, stats.messageParseFail.Snapshot().Count()) + require.EqualValues(t, 0, stats.addressedCallSignatureValidationFail.Snapshot().Count()) require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) }, err: &common.AppError{Code: ParseErrCode},