From c2da67db92f8d1f00dc4525b2e05aa4e09e6d28e Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Tue, 6 Aug 2024 14:22:13 -0700 Subject: [PATCH 01/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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 f64d7ac036e72545140ad270d3c42074007a3c67 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Mon, 19 Aug 2024 14:44:16 -0700 Subject: [PATCH 09/14] Revert "disable always signing" This reverts commit 008bc37f50d2df0ef2b31f1470069ce543bca8a9. --- plugin/evm/vm.go | 1 + warp/handlers/validator_uptime_handler.go | 38 +++++++++++++++++++ .../handlers/validator_uptime_handler_test.go | 35 +++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 warp/handlers/validator_uptime_handler.go create mode 100644 warp/handlers/validator_uptime_handler_test.go diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 2c6dfd55b9..dd3af26df8 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/warp/handlers/validator_uptime_handler.go b/warp/handlers/validator_uptime_handler.go new file mode 100644 index 0000000000..7b9e286304 --- /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/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 new file mode 100644 index 0000000000..e0a009faad --- /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/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 10/14] 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 11/14] 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 20388fb42a27830a8942592b5a92c5211c7dce7a Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Tue, 20 Aug 2024 10:58:49 -0700 Subject: [PATCH 12/14] use new interface model --- plugin/evm/vm.go | 1 - warp/handlers/validator_uptime_handler.go | 38 ------------------- .../handlers/validator_uptime_handler_test.go | 35 ----------------- warp/messages/validator_uptime.go | 19 ++++++++++ warp/messages/validator_uptime_test.go | 22 +++++++++++ 5 files changed, 41 insertions(+), 74 deletions(-) delete mode 100644 warp/handlers/validator_uptime_handler.go delete mode 100644 warp/handlers/validator_uptime_handler_test.go create mode 100644 warp/messages/validator_uptime_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)) -} diff --git a/warp/messages/validator_uptime.go b/warp/messages/validator_uptime.go index 3d3e4dd5dd..01534eed60 100644 --- a/warp/messages/validator_uptime.go +++ b/warp/messages/validator_uptime.go @@ -4,11 +4,15 @@ package messages import ( + "errors" "fmt" "github.com/ava-labs/avalanchego/ids" + "github.com/ethereum/go-ethereum/log" ) +var errInvalidRequest = errors.New("invalid request") + // ValidatorUptime is signed when the ValidationID is known and the validator // has been up for TotalUptime seconds. type ValidatorUptime struct { @@ -49,3 +53,18 @@ func (b *ValidatorUptime) Bytes() []byte { func (b *ValidatorUptime) initialize(bytes []byte) { b.bytes = bytes } + +// VerifyMesssage returns nil if the message is valid. +func (b *ValidatorUptime) VerifyMesssage(sourceAddress []byte) error { + // DO NOT USE THIS CODE AS IS IN PRODUCTION. + + // TODO: Does nil/empty SourceAddress matter? + if len(sourceAddress) != 0 { + return errInvalidRequest + } + + log.Info("Received validator uptime message", "validationID", b.ValidationID, "totalUptime", b.TotalUptime) + log.Warn("Signing validator uptime message by default, not production behavior", "validationID", b.ValidationID, "totalUptime", b.TotalUptime) + + return nil +} diff --git a/warp/messages/validator_uptime_test.go b/warp/messages/validator_uptime_test.go new file mode 100644 index 0000000000..2f59e0079b --- /dev/null +++ b/warp/messages/validator_uptime_test.go @@ -0,0 +1,22 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package messages + +import ( + "testing" + + "github.com/ava-labs/avalanchego/ids" + "github.com/stretchr/testify/require" +) + +func TestVerifyMessage(t *testing.T) { + require := require.New(t) + + validationID := ids.GenerateTestID() + totalUptime := uint64(1_000_000) // arbitrary value + vdrUptime, err := NewValidatorUptime(validationID, totalUptime) + require.NoError(err) + + require.NoError(vdrUptime.VerifyMesssage(nil)) +} From bb72fdd0d80a20fd0e6a354c4d84452bc891a8af Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Tue, 20 Aug 2024 11:14:12 -0700 Subject: [PATCH 13/14] 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 fe05d33d3b2d6ca036ff56dad7e3b920f7645233 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Tue, 20 Aug 2024 11:14:12 -0700 Subject: [PATCH 14/14] 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") } }