From 551d07cc8f28df3d94361422cae5a453e902de7c Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Tue, 28 Nov 2023 11:32:21 -0500 Subject: [PATCH] Cleanup warp related code (#995) * Cleanup warp related code * Revert back to pass rules via pointer in handlePrecompileAccept * goimports * Remove unused var * Update signature aggregator new comment * Update README so it applies to both Coreth and Subnet-EVM --- plugin/evm/config.go | 1 - plugin/evm/vm_test.go | 116 ----------------------- plugin/evm/vm_warp_test.go | 117 ++++++++++++++++++++++++ warp/aggregator/aggregator.go | 3 +- warp/handlers/signature_request_test.go | 8 -- x/warp/README.md | 15 +-- 6 files changed, 123 insertions(+), 137 deletions(-) diff --git a/plugin/evm/config.go b/plugin/evm/config.go index 708bdfebc8..7f4ca902d6 100644 --- a/plugin/evm/config.go +++ b/plugin/evm/config.go @@ -17,7 +17,6 @@ import ( const ( defaultAcceptorQueueLimit = 64 // Provides 2 minutes of buffer (2s block target) for a commit delay defaultPruningEnabled = true - defaultPruneWarpDB = false defaultCommitInterval = 4096 defaultTrieCleanCache = 512 defaultTrieDirtyCache = 512 diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index d554ff3771..099bddfe35 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -3264,119 +3264,3 @@ func TestCrossChainMessagestoVM(t *testing.T) { require.NoError(err) require.True(calledSendCrossChainAppResponseFn, "sendCrossChainAppResponseFn was not called") } - -func TestMessageSignatureRequestsToVM(t *testing.T) { - _, vm, _, appSender := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") - - defer func() { - err := vm.Shutdown(context.Background()) - require.NoError(t, err) - }() - - // Generate a new warp unsigned message and add to warp backend - warpMessage, err := avalancheWarp.NewUnsignedMessage(vm.ctx.NetworkID, vm.ctx.ChainID, []byte{1, 2, 3}) - require.NoError(t, err) - - // 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()) - require.NoError(t, err) - - tests := map[string]struct { - messageID ids.ID - expectedResponse [bls.SignatureLen]byte - }{ - "known": { - messageID: warpMessage.ID(), - expectedResponse: signature, - }, - "unknown": { - messageID: ids.GenerateTestID(), - expectedResponse: [bls.SignatureLen]byte{}, - }, - } - - for name, test := range tests { - calledSendAppResponseFn := false - appSender.SendAppResponseF = func(ctx context.Context, nodeID ids.NodeID, requestID uint32, responseBytes []byte) error { - calledSendAppResponseFn = true - var response message.SignatureResponse - _, err := message.Codec.Unmarshal(responseBytes, &response) - require.NoError(t, err) - require.Equal(t, test.expectedResponse, response.Signature) - - return nil - } - t.Run(name, func(t *testing.T) { - var signatureRequest message.Request = message.MessageSignatureRequest{ - MessageID: test.messageID, - } - - requestBytes, err := message.Codec.Marshal(message.Version, &signatureRequest) - require.NoError(t, err) - - // Send the app request and make sure we called SendAppResponseFn - deadline := time.Now().Add(60 * time.Second) - err = vm.Network.AppRequest(context.Background(), ids.GenerateTestNodeID(), 1, deadline, requestBytes) - require.NoError(t, err) - require.True(t, calledSendAppResponseFn) - }) - } -} - -func TestBlockSignatureRequestsToVM(t *testing.T) { - _, vm, _, appSender := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") - - defer func() { - err := vm.Shutdown(context.Background()) - require.NoError(t, err) - }() - - lastAcceptedID, err := vm.LastAccepted(context.Background()) - require.NoError(t, err) - - signature, err := vm.warpBackend.GetBlockSignature(lastAcceptedID) - require.NoError(t, err) - - tests := map[string]struct { - blockID ids.ID - expectedResponse [bls.SignatureLen]byte - }{ - "known": { - blockID: lastAcceptedID, - expectedResponse: signature, - }, - "unknown": { - blockID: ids.GenerateTestID(), - expectedResponse: [bls.SignatureLen]byte{}, - }, - } - - for name, test := range tests { - calledSendAppResponseFn := false - appSender.SendAppResponseF = func(ctx context.Context, nodeID ids.NodeID, requestID uint32, responseBytes []byte) error { - calledSendAppResponseFn = true - var response message.SignatureResponse - _, err := message.Codec.Unmarshal(responseBytes, &response) - require.NoError(t, err) - require.Equal(t, test.expectedResponse, response.Signature) - - return nil - } - t.Run(name, func(t *testing.T) { - var signatureRequest message.Request = message.BlockSignatureRequest{ - BlockID: test.blockID, - } - - requestBytes, err := message.Codec.Marshal(message.Version, &signatureRequest) - require.NoError(t, err) - - // Send the app request and make sure we called SendAppResponseFn - deadline := time.Now().Add(60 * time.Second) - err = vm.Network.AppRequest(context.Background(), ids.GenerateTestNodeID(), 1, deadline, requestBytes) - require.NoError(t, err) - require.True(t, calledSendAppResponseFn) - }) - } -} diff --git a/plugin/evm/vm_warp_test.go b/plugin/evm/vm_warp_test.go index c431389439..57ec319410 100644 --- a/plugin/evm/vm_warp_test.go +++ b/plugin/evm/vm_warp_test.go @@ -27,6 +27,7 @@ import ( "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/eth/tracers" "github.com/ava-labs/subnet-evm/params" + "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/predicate" subnetEVMUtils "github.com/ava-labs/subnet-evm/utils" @@ -583,3 +584,119 @@ func TestReceiveWarpMessage(t *testing.T) { require.NoError(err) require.JSONEq(string(txTraceResultBytes), string(blockTxTraceResultBytes)) } + +func TestMessageSignatureRequestsToVM(t *testing.T) { + _, vm, _, appSender := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") + + defer func() { + err := vm.Shutdown(context.Background()) + require.NoError(t, err) + }() + + // Generate a new warp unsigned message and add to warp backend + warpMessage, err := avalancheWarp.NewUnsignedMessage(vm.ctx.NetworkID, vm.ctx.ChainID, []byte{1, 2, 3}) + require.NoError(t, err) + + // 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()) + require.NoError(t, err) + + tests := map[string]struct { + messageID ids.ID + expectedResponse [bls.SignatureLen]byte + }{ + "known": { + messageID: warpMessage.ID(), + expectedResponse: signature, + }, + "unknown": { + messageID: ids.GenerateTestID(), + expectedResponse: [bls.SignatureLen]byte{}, + }, + } + + for name, test := range tests { + calledSendAppResponseFn := false + appSender.SendAppResponseF = func(ctx context.Context, nodeID ids.NodeID, requestID uint32, responseBytes []byte) error { + calledSendAppResponseFn = true + var response message.SignatureResponse + _, err := message.Codec.Unmarshal(responseBytes, &response) + require.NoError(t, err) + require.Equal(t, test.expectedResponse, response.Signature) + + return nil + } + t.Run(name, func(t *testing.T) { + var signatureRequest message.Request = message.MessageSignatureRequest{ + MessageID: test.messageID, + } + + requestBytes, err := message.Codec.Marshal(message.Version, &signatureRequest) + require.NoError(t, err) + + // Send the app request and make sure we called SendAppResponseFn + deadline := time.Now().Add(60 * time.Second) + err = vm.Network.AppRequest(context.Background(), ids.GenerateTestNodeID(), 1, deadline, requestBytes) + require.NoError(t, err) + require.True(t, calledSendAppResponseFn) + }) + } +} + +func TestBlockSignatureRequestsToVM(t *testing.T) { + _, vm, _, appSender := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") + + defer func() { + err := vm.Shutdown(context.Background()) + require.NoError(t, err) + }() + + lastAcceptedID, err := vm.LastAccepted(context.Background()) + require.NoError(t, err) + + signature, err := vm.warpBackend.GetBlockSignature(lastAcceptedID) + require.NoError(t, err) + + tests := map[string]struct { + blockID ids.ID + expectedResponse [bls.SignatureLen]byte + }{ + "known": { + blockID: lastAcceptedID, + expectedResponse: signature, + }, + "unknown": { + blockID: ids.GenerateTestID(), + expectedResponse: [bls.SignatureLen]byte{}, + }, + } + + for name, test := range tests { + calledSendAppResponseFn := false + appSender.SendAppResponseF = func(ctx context.Context, nodeID ids.NodeID, requestID uint32, responseBytes []byte) error { + calledSendAppResponseFn = true + var response message.SignatureResponse + _, err := message.Codec.Unmarshal(responseBytes, &response) + require.NoError(t, err) + require.Equal(t, test.expectedResponse, response.Signature) + + return nil + } + t.Run(name, func(t *testing.T) { + var signatureRequest message.Request = message.BlockSignatureRequest{ + BlockID: test.blockID, + } + + requestBytes, err := message.Codec.Marshal(message.Version, &signatureRequest) + require.NoError(t, err) + + // Send the app request and make sure we called SendAppResponseFn + deadline := time.Now().Add(60 * time.Second) + err = vm.Network.AppRequest(context.Background(), ids.GenerateTestNodeID(), 1, deadline, requestBytes) + require.NoError(t, err) + require.True(t, calledSendAppResponseFn) + }) + } +} diff --git a/warp/aggregator/aggregator.go b/warp/aggregator/aggregator.go index 7f53075c55..60a0279f1e 100644 --- a/warp/aggregator/aggregator.go +++ b/warp/aggregator/aggregator.go @@ -39,8 +39,7 @@ type Aggregator struct { client SignatureGetter } -// New returns a signature aggregator for the chain with the given [state] on the -// given [subnetID], and where [client] can be used to fetch signatures from validators. +// New returns a signature aggregator that will attempt to aggregate signatures from [validators]. func New(client SignatureGetter, validators []*avalancheWarp.Validator, totalWeight uint64) *Aggregator { return &Aggregator{ client: client, diff --git a/warp/handlers/signature_request_test.go b/warp/handlers/signature_request_test.go index 2df20bbb50..f920b43812 100644 --- a/warp/handlers/signature_request_test.go +++ b/warp/handlers/signature_request_test.go @@ -56,11 +56,9 @@ func TestMessageSignatureHandler(t *testing.T) { require.EqualValues(t, 1, stats.messageSignatureRequest.Count()) require.EqualValues(t, 1, stats.messageSignatureHit.Count()) require.EqualValues(t, 0, stats.messageSignatureMiss.Count()) - require.Greater(t, stats.messageSignatureRequestDuration.Value(), int64(0)) require.EqualValues(t, 0, stats.blockSignatureRequest.Count()) require.EqualValues(t, 0, stats.blockSignatureHit.Count()) require.EqualValues(t, 0, stats.blockSignatureMiss.Count()) - require.EqualValues(t, stats.blockSignatureRequestDuration.Value(), int64(0)) }, }, "unknown message": { @@ -73,11 +71,9 @@ func TestMessageSignatureHandler(t *testing.T) { require.EqualValues(t, 1, stats.messageSignatureRequest.Count()) require.EqualValues(t, 0, stats.messageSignatureHit.Count()) require.EqualValues(t, 1, stats.messageSignatureMiss.Count()) - require.Greater(t, stats.messageSignatureRequestDuration.Value(), int64(0)) require.EqualValues(t, 0, stats.blockSignatureRequest.Count()) require.EqualValues(t, 0, stats.blockSignatureHit.Count()) require.EqualValues(t, 0, stats.blockSignatureMiss.Count()) - require.EqualValues(t, stats.blockSignatureRequestDuration.Value(), int64(0)) }, }, } @@ -158,11 +154,9 @@ func TestBlockSignatureHandler(t *testing.T) { require.EqualValues(t, 0, stats.messageSignatureRequest.Count()) require.EqualValues(t, 0, stats.messageSignatureHit.Count()) require.EqualValues(t, 0, stats.messageSignatureMiss.Count()) - require.EqualValues(t, stats.messageSignatureRequestDuration.Value(), int64(0)) require.EqualValues(t, 1, stats.blockSignatureRequest.Count()) require.EqualValues(t, 1, stats.blockSignatureHit.Count()) require.EqualValues(t, 0, stats.blockSignatureMiss.Count()) - require.Greater(t, stats.blockSignatureRequestDuration.Value(), int64(0)) }, }, "unknown block": { @@ -175,11 +169,9 @@ func TestBlockSignatureHandler(t *testing.T) { require.EqualValues(t, 0, stats.messageSignatureRequest.Count()) require.EqualValues(t, 0, stats.messageSignatureHit.Count()) require.EqualValues(t, 0, stats.messageSignatureMiss.Count()) - require.EqualValues(t, stats.messageSignatureRequestDuration.Value(), int64(0)) require.EqualValues(t, 1, stats.blockSignatureRequest.Count()) require.EqualValues(t, 0, stats.blockSignatureHit.Count()) require.EqualValues(t, 1, stats.blockSignatureMiss.Count()) - require.Greater(t, stats.blockSignatureRequestDuration.Value(), int64(0)) }, }, } diff --git a/x/warp/README.md b/x/warp/README.md index 1a72e0d476..9c702ed049 100644 --- a/x/warp/README.md +++ b/x/warp/README.md @@ -1,13 +1,8 @@ # Avalanche Warp Messaging -> **Warning** -> Avalanche Warp Messaging is currently in experimental mode to be used only on ephemeral test networks. -> -> Breaking changes to Avalanche Warp Messaging integration into Subnet-EVM may still be made. - Avalanche Warp Messaging offers a basic primitive to enable Cross-Subnet communication on the Avalanche Network. -It is intended to allow communication between arbitrary Custom Virtual Machines (including, but not limited to Subnet-EVM). +It is intended to allow communication between arbitrary Custom Virtual Machines (including, but not limited to Subnet-EVM and Coreth). ## How does Avalanche Warp Messaging Work @@ -51,7 +46,7 @@ Additionally, the `SourceChainID` is excluded because anyone parsing the chain c - `sender` - The `messageID` of the unsigned message (sha256 of the unsigned message) -The actual `message` is the entire [Avalanche Warp Unsigned Message](https://github.com/ava-labs/avalanchego/blob/master/vms/platformvm/warp/unsigned_message.go#L14) including the Subnet-EVM [Addressed Payload](../../../warp/payload/payload.go). This is emitted as the unindexed data in the log. +The actual `message` is the entire [Avalanche Warp Unsigned Message](https://github.com/ava-labs/avalanchego/blob/master/vms/platformvm/warp/unsigned_message.go#L14) including an [AddressedCall](https://github.com/ava-labs/avalanchego/tree/v1.10.15/vms/platformvm/warp/payload). The unsigned message is emitted as the unindexed data in the log. #### getVerifiedMessage @@ -70,7 +65,7 @@ This pre-verification is performed using the ProposerVM Block header during [blo #### getBlockchainID -`getBlockchainID` returns the blockchainID of the blockchain that Subnet-EVM is running on. +`getBlockchainID` returns the blockchainID of the blockchain that the VM is running on. This is different from the conventional Ethereum ChainID registered to [ChainList](https://chainlist.org/). @@ -120,7 +115,7 @@ This means verifying the Warp Message and therefore the state transition on a bl The Avalanche P-Chain tracks only its current state and reverse diff layers (reversing the changes from past blocks) in order to re-calculate the validator set at a historical height. This means calculating a very old validator set that is used to verify a Warp Message in an old block may become prohibitively expensive. -Therefore, we need a heuristic to ensure that the network can correctly re-process old blocks (note: re-processing old blocks is a requirement to perform bootstrapping and is used in some VMs including Subnet-EVM to serve or verify historical data). +Therefore, we need a heuristic to ensure that the network can correctly re-process old blocks (note: re-processing old blocks is a requirement to perform bootstrapping and is used in some VMs to serve or verify historical data). As a result, we require that the block itself provides a deterministic hint which determines which Avalanche Warp Messages were considered valid/invalid during the block's execution. This ensures that we can always re-process blocks and use the hint to decide whether an Avalanche Warp Message should be treated as valid/invalid even after the P-Chain state that was used at the original execution time may no longer support fast lookups. @@ -143,7 +138,7 @@ In contrast, Avalanche Warp Messages are validated within the context of an exac #### Guarantees Offered by Warp Precompile -The Warp Precompile was designed with the intention of minimizing the trusted computing base for Subnet-EVM. Therefore, it makes several tradeoffs which encourage users to use protocols built ON TOP of the Warp Precompile itself as opposed to directly using the Warp Precompile. +The Warp Precompile was designed with the intention of minimizing the trusted computing base for the VM as much as possible. Therefore, it makes several tradeoffs which encourage users to use protocols built ON TOP of the Warp Precompile itself as opposed to directly using the Warp Precompile. The Warp Precompile itself provides ONLY the following ability: