diff --git a/config/api_config.go b/config/api_config.go index 25a77f6a..e68d73c4 100644 --- a/config/api_config.go +++ b/config/api_config.go @@ -1,3 +1,6 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + package config import ( diff --git a/go.mod b/go.mod index ab775f17..b01056da 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module github.com/ava-labs/awm-relayer go 1.22.6 require ( - github.com/ava-labs/avalanchego v1.11.10 - github.com/ava-labs/coreth v0.13.7 - github.com/ava-labs/subnet-evm v0.6.8 + github.com/ava-labs/avalanchego v1.11.11-0.20240813203340-ab83fb41528d + github.com/ava-labs/coreth v0.13.8-fixed-genesis-upgrade.0.20240813194342-7635a96aa180 + github.com/ava-labs/subnet-evm v0.6.9-0.20240816202746-18633729a0cd github.com/ava-labs/teleporter v1.0.6 github.com/aws/aws-sdk-go-v2 v1.30.5 github.com/aws/aws-sdk-go-v2/config v1.27.9 diff --git a/go.sum b/go.sum index 7f23fd94..fe1cb1de 100644 --- a/go.sum +++ b/go.sum @@ -58,12 +58,12 @@ github.com/alexliesenfeld/health v0.8.0/go.mod h1:TfNP0f+9WQVWMQRzvMUjlws4ceXKEL 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.10 h1:QujciF5OEp5FwAoe/RciFF/i47rxU5rkEr6fVuUBS1Q= -github.com/ava-labs/avalanchego v1.11.10/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/subnet-evm v0.6.8 h1:IrHGajBYWs692YIYdd5J0oVWWt88Q/XAZQq/dOtkHFw= -github.com/ava-labs/subnet-evm v0.6.8/go.mod h1:qt8DXyGm40CY9yffNOe1+4yUyL9mD3v5RPWqAuGj5u4= +github.com/ava-labs/avalanchego v1.11.11-0.20240813203340-ab83fb41528d h1:LyrKJL9avIIxBY3uTcS2dFtUMBFmI2QpAgG6qYTdA6s= +github.com/ava-labs/avalanchego v1.11.11-0.20240813203340-ab83fb41528d/go.mod h1:UkyrRDXK2E15Lq2abyae2Pt+JsWvgsg1pe0/AtoMyAM= +github.com/ava-labs/coreth v0.13.8-fixed-genesis-upgrade.0.20240813194342-7635a96aa180 h1:6aIHp7wbyGVYdhHVQUbG7BEcbCMEQ5SYopPPJyipyvk= +github.com/ava-labs/coreth v0.13.8-fixed-genesis-upgrade.0.20240813194342-7635a96aa180/go.mod h1:/wNBVq7J7wlC2Kbov7kk6LV5xZvau7VF9zwTVOeyAjY= +github.com/ava-labs/subnet-evm v0.6.9-0.20240816202746-18633729a0cd h1:5kJTOhmIhIiobseQ+RYuLg4UyodN+CSAdW1c0hx1R2Y= +github.com/ava-labs/subnet-evm v0.6.9-0.20240816202746-18633729a0cd/go.mod h1:QfIzh7YxKj97jbendOHQbaAxM7SMj5MWdV13o1VLn70= github.com/ava-labs/teleporter v1.0.6 h1:buZULenvJLUUMyPihiSvGMag5/rm6oF8zL8YUw7NXxE= github.com/ava-labs/teleporter v1.0.6/go.mod h1:JRfVZzLrb4qFZz2M5/c8L7cdN4A4JWJd7GIEzVeC+sg= github.com/aws/aws-sdk-go-v2 v1.30.5 h1:mWSRTwQAb0aLE17dSzztCVJWI9+cRMgqebndjwDyK0g= diff --git a/peers/external_handler.go b/peers/external_handler.go index 7b6417ce..be4e0518 100644 --- a/peers/external_handler.go +++ b/peers/external_handler.go @@ -90,6 +90,9 @@ func (h *RelayerExternalHandler) HandleInbound(_ context.Context, inboundMessage zap.Stringer("from", inboundMessage.NodeID()), ) if inboundMessage.Op() == message.AppResponseOp || inboundMessage.Op() == message.AppErrorOp { + if inboundMessage.Op() == message.AppErrorOp { + h.log.Debug("Received AppError message", zap.Stringer("message", inboundMessage.Message())) + } h.registerAppResponse(inboundMessage) } else { h.log.Debug("Ignoring message", zap.Stringer("op", inboundMessage.Op())) diff --git a/relayer/application_relayer.go b/relayer/application_relayer.go index 89a33194..c1c93910 100644 --- a/relayer/application_relayer.go +++ b/relayer/application_relayer.go @@ -204,6 +204,7 @@ func (r *ApplicationRelayer) ProcessMessage(handler messages.MessageHandler) (co if r.sourceWarpSignatureClient == nil { signedMessage, err = r.signatureAggregator.CreateSignedMessage( unsignedMessage, + nil, r.signingSubnetID, r.warpQuorum.QuorumNumerator, ) diff --git a/relayer/config/config.go b/relayer/config/config.go index 57ea0822..3f643dd2 100644 --- a/relayer/config/config.go +++ b/relayer/config/config.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "net/url" + "time" basecfg "github.com/ava-labs/awm-relayer/config" "github.com/ava-labs/awm-relayer/peers" @@ -67,6 +68,9 @@ type Config struct { DeciderURL string `mapstructure:"decider-url" json:"decider-url"` SignatureCacheSize uint64 `mapstructure:"signature-cache-size" json:"signature-cache-size"` + // mapstructure doesn't handle time.Time out of the box so handle it manually + EtnaTime time.Time `json:"etna-time"` + // convenience field to fetch a blockchain's subnet ID blockchainIDToSubnetID map[ids.ID]ids.ID overwrittenOptions []string diff --git a/relayer/config/keys.go b/relayer/config/keys.go index 1c426fe0..fa211fc2 100644 --- a/relayer/config/keys.go +++ b/relayer/config/keys.go @@ -24,4 +24,5 @@ const ( ManualWarpMessagesKey = "manual-warp-messages" DBWriteIntervalSecondsKey = "db-write-interval-seconds" SignatureCacheSizeKey = "signature-cache-size" + EtnaTimeKey = "etna-time" ) diff --git a/relayer/config/viper.go b/relayer/config/viper.go index 507bd952..4e0e279b 100644 --- a/relayer/config/viper.go +++ b/relayer/config/viper.go @@ -84,6 +84,9 @@ func BuildConfig(v *viper.Viper) (Config, error) { return cfg, fmt.Errorf("failed to unmarshal viper config: %w", err) } + // Manually set EtnaTime field since it's not automatically parseable using mapstructure + cfg.EtnaTime = v.GetTime(EtnaTimeKey) + // Explicitly overwrite the configured account private key // If account-private-key is set as a flag or environment variable, // overwrite all destination subnet configurations to use that key diff --git a/relayer/main/main.go b/relayer/main/main.go index 95d25a4b..06e4c6e5 100644 --- a/relayer/main/main.go +++ b/relayer/main/main.go @@ -227,6 +227,7 @@ func main() { prometheus.DefaultRegisterer, ), messageCreator, + cfg.EtnaTime, ) if err != nil { logger.Fatal("Failed to create signature aggregator", zap.Error(err)) diff --git a/scripts/versions.sh b/scripts/versions.sh index 641974a9..018f5d67 100755 --- a/scripts/versions.sh +++ b/scripts/versions.sh @@ -17,12 +17,14 @@ function getDepVersion() { export GO_VERSION=${GO_VERSION:-$(getDepVersion go)} # Don't export them as they're used in the context of other calls -AVALANCHEGO_VERSION=${AVALANCHEGO_VERSION:-$(getDepVersion github.com/ava-labs/avalanchego)} +# TODO: undo this hack once go.mod is referring to a tag rather than a commit +#AVALANCHEGO_VERSION=${AVALANCHEGO_VERSION:-$(getDepVersion github.com/ava-labs/avalanchego)} +AVALANCHEGO_VERSION=${AVALANCHEGO_VERSION:-ab83fb41528de93c1790301cdd67a07dda9299f0} GINKGO_VERSION=${GINKGO_VERSION:-$(getDepVersion github.com/onsi/ginkgo/v2)} # TODO: undo this hack once go.mod is referring to a tag rather than a commit #SUBNET_EVM_VERSION=${SUBNET_EVM_VERSION:-$(getDepVersion github.com/ava-labs/subnet-evm)} -SUBNET_EVM_VERSION=${SUBNET_EVM_VERSION:-update-avago-teleporter} +SUBNET_EVM_VERSION=${SUBNET_EVM_VERSION:-18633729a0cde7d695616e14b77873957a2b59c2} # Set golangci-lint version GOLANGCI_LINT_VERSION=${GOLANGCI_LINT_VERSION:-'v1.60'} diff --git a/signature-aggregator/README.md b/signature-aggregator/README.md index 1c8b60a1..ed6e9e97 100644 --- a/signature-aggregator/README.md +++ b/signature-aggregator/README.md @@ -69,9 +69,9 @@ curl --location 'https://api.avax-test.network/ext/bc/C/rpc' \ The topic of the message will be `0x56600c567728a800c0aa927500f831cb451df66a7af570eb4df4dfbf4674887d` which is the output of`cast keccak "SendWarpMessage(address,bytes32,bytes)"` 4. Use the data field of the log message found in step 2 and send it to the locally running service via curl. ```bash -curl --location 'http://localhost:8080/aggregate-signatures/by-raw-message' \ +curl --location 'http://localhost:8080/aggregate-signatures' \ --header 'Content-Type: application/json' \ --data '{ - "data": "", + "message": "" }' ``` diff --git a/signature-aggregator/aggregator/aggregator.go b/signature-aggregator/aggregator/aggregator.go index a48ac728..a284c224 100644 --- a/signature-aggregator/aggregator/aggregator.go +++ b/signature-aggregator/aggregator/aggregator.go @@ -15,7 +15,9 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/message" + networkP2P "github.com/ava-labs/avalanchego/network/p2p" "github.com/ava-labs/avalanchego/proto/pb/p2p" + "github.com/ava-labs/avalanchego/proto/pb/sdk" "github.com/ava-labs/avalanchego/subnets" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/bls" @@ -26,9 +28,10 @@ import ( "github.com/ava-labs/awm-relayer/signature-aggregator/aggregator/cache" "github.com/ava-labs/awm-relayer/signature-aggregator/metrics" "github.com/ava-labs/awm-relayer/utils" - coreEthMsg "github.com/ava-labs/coreth/plugin/evm/message" + corethMsg "github.com/ava-labs/coreth/plugin/evm/message" msg "github.com/ava-labs/subnet-evm/plugin/evm/message" "go.uber.org/zap" + "google.golang.org/protobuf/proto" ) type blsSignatureBuf [bls.SignatureLen]byte @@ -42,8 +45,8 @@ const ( ) var ( - codec = msg.Codec - coreEthCodec = coreEthMsg.Codec + codec = msg.Codec + corethCodec = corethMsg.Codec // Errors errNotEnoughSignatures = errors.New("failed to collect a threshold of signatures") @@ -60,6 +63,7 @@ type SignatureAggregator struct { subnetsMapLock sync.RWMutex metrics *metrics.SignatureAggregatorMetrics cache *cache.Cache + etnaTime time.Time } func NewSignatureAggregator( @@ -68,6 +72,7 @@ func NewSignatureAggregator( signatureCacheSize uint64, metrics *metrics.SignatureAggregatorMetrics, messageCreator message.Creator, + etnaTime time.Time, ) (*SignatureAggregator, error) { cache, err := cache.NewCache(signatureCacheSize, logger) if err != nil { @@ -84,6 +89,7 @@ func NewSignatureAggregator( messageCreator: messageCreator, currentRequestID: atomic.Uint32{}, cache: cache, + etnaTime: etnaTime, } sa.currentRequestID.Store(rand.Uint32()) return &sa, nil @@ -91,6 +97,7 @@ func NewSignatureAggregator( func (s *SignatureAggregator) CreateSignedMessage( unsignedMessage *avalancheWarp.UnsignedMessage, + justification []byte, inputSigningSubnet ids.ID, quorumPercentage uint64, ) (*avalancheWarp.Message, error) { @@ -176,19 +183,7 @@ func (s *SignatureAggregator) CreateSignedMessage( )) } - // TODO: remove this special handling and replace with ACP-118 interface once available - var reqBytes []byte - if sourceSubnet == constants.PrimaryNetworkID { - req := coreEthMsg.MessageSignatureRequest{ - MessageID: unsignedMessage.ID(), - } - reqBytes, err = coreEthMsg.RequestToBytes(coreEthCodec, req) - } else { - req := msg.MessageSignatureRequest{ - MessageID: unsignedMessage.ID(), - } - reqBytes, err = msg.RequestToBytes(codec, req) - } + reqBytes, err := s.marshalRequest(unsignedMessage, justification, sourceSubnet) if err != nil { msg := "Failed to marshal request bytes" s.logger.Error( @@ -524,14 +519,13 @@ func (s *SignatureAggregator) isValidSignatureResponse( return blsSignatureBuf{}, false } - var sigResponse msg.SignatureResponse - if _, err := msg.Codec.Unmarshal(appResponse.AppBytes, &sigResponse); err != nil { + signature, err := s.unmarshalResponse(appResponse.AppBytes) + if err != nil { s.logger.Error( "Error unmarshaling signature response", zap.Error(err), ) } - signature := sigResponse.Signature // If the node returned an empty signature, then it has not yet seen the warp message. Retry later. emptySignature := blsSignatureBuf{} @@ -543,6 +537,15 @@ func (s *SignatureAggregator) isValidSignatureResponse( return blsSignatureBuf{}, false } + if len(signature) != bls.SignatureLen { + s.logger.Debug( + "Response signature has incorrect length", + zap.Int("actual", len(signature)), + zap.Int("expected", bls.SignatureLen), + ) + return blsSignatureBuf{}, false + } + sig, err := bls.SignatureFromBytes(signature[:]) if err != nil { s.logger.Debug( @@ -590,3 +593,65 @@ func (s *SignatureAggregator) aggregateSignatures( } return aggSig, vdrBitSet, nil } + +// TODO: refactor this to remove special handling based on etnaTime +// after Etna release, along with related config and testing code +func (s *SignatureAggregator) marshalRequest( + unsignedMessage *avalancheWarp.UnsignedMessage, + justification []byte, + sourceSubnet ids.ID, +) ([]byte, error) { + if s.etnaActivated() { + // Post-Etna case + messageBytes, err := proto.Marshal( + &sdk.SignatureRequest{ + Message: unsignedMessage.Bytes(), + Justification: justification, + }, + ) + if err != nil { + return nil, err + } + return networkP2P.PrefixMessage( + networkP2P.ProtocolPrefix(networkP2P.SignatureRequestHandlerID), + messageBytes, + ), nil + } else { + // Pre-Etna case + if sourceSubnet == constants.PrimaryNetworkID { + req := corethMsg.MessageSignatureRequest{ + MessageID: unsignedMessage.ID(), + } + return corethMsg.RequestToBytes(corethCodec, req) + } else { + req := msg.MessageSignatureRequest{ + MessageID: unsignedMessage.ID(), + } + return msg.RequestToBytes(codec, req) + } + } +} + +func (s *SignatureAggregator) unmarshalResponse(responseBytes []byte) (blsSignatureBuf, error) { + if s.etnaActivated() { + // Post-Etna case + var sigResponse sdk.SignatureResponse + err := proto.Unmarshal(responseBytes, &sigResponse) + if err != nil { + return blsSignatureBuf{}, err + } + return blsSignatureBuf(sigResponse.Signature), nil + } else { + // Pre-Etna case + var sigResponse msg.SignatureResponse + _, err := msg.Codec.Unmarshal(responseBytes, &sigResponse) + if err != nil { + return blsSignatureBuf{}, err + } + return sigResponse.Signature, nil + } +} + +func (s *SignatureAggregator) etnaActivated() bool { + return !s.etnaTime.IsZero() && s.etnaTime.Before(time.Now()) +} diff --git a/signature-aggregator/aggregator/aggregator_test.go b/signature-aggregator/aggregator/aggregator_test.go index 13a6952c..8876a646 100644 --- a/signature-aggregator/aggregator/aggregator_test.go +++ b/signature-aggregator/aggregator/aggregator_test.go @@ -2,6 +2,7 @@ package aggregator import ( "testing" + "time" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/message" @@ -43,6 +44,8 @@ func instantiateAggregator(t *testing.T) ( 1024, sigAggMetrics, messageCreator, + // Setting the etnaTime to a minute ago so that the post-etna code path is used in the test + time.Now().Add(-1*time.Minute), ) require.Equal(t, err, nil) return aggregator, mockNetwork @@ -61,7 +64,7 @@ func TestCreateSignedMessageFailsWithNoValidators(t *testing.T) { }, nil, ) - _, err = aggregator.CreateSignedMessage(msg, ids.Empty, 80) + _, err = aggregator.CreateSignedMessage(msg, nil, ids.Empty, 80) require.ErrorContains(t, err, "no signatures") } @@ -78,7 +81,7 @@ func TestCreateSignedMessageFailsWithoutSufficientConnectedStake(t *testing.T) { }, nil, ) - _, err = aggregator.CreateSignedMessage(msg, ids.Empty, 80) + _, err = aggregator.CreateSignedMessage(msg, nil, ids.Empty, 80) require.ErrorContains( t, err, diff --git a/signature-aggregator/api/api.go b/signature-aggregator/api/api.go index e5a5829b..1717b3a9 100644 --- a/signature-aggregator/api/api.go +++ b/signature-aggregator/api/api.go @@ -26,8 +26,11 @@ const ( // Defines a request interface for signature aggregation for a raw unsigned message. type AggregateSignatureRequest struct { - // Required. hex-encoded message, optionally prefixed with "0x". - UnsignedMessage string `json:"unsigned-message"` + // Required: either Message or Justification must be provided. + // hex-encoded message, optionally prefixed with "0x". + Message string `json:"message"` + // hex-encoded justification, optionally prefixed with "0x". + Justification string `json:"justification"` // Optional hex or cb58 encoded signing subnet ID. If omitted will default to the subnetID of the source blockchain SigningSubnetID string `json:"signing-subnet-id"` // Optional. Integer from 0 to 100 representing the percentage of the quorum that is required to sign the message @@ -75,6 +78,15 @@ func writeJSONError( } } +func isEmptyOrZeroes(bytes []byte) bool { + for _, b := range bytes { + if b != 0 { + return false + } + } + return true +} + func signatureAggregationAPIHandler( logger logging.Logger, metrics *metrics.SignatureAggregatorMetrics, @@ -94,25 +106,49 @@ func signatureAggregationAPIHandler( } var decodedMessage []byte decodedMessage, err = hex.DecodeString( - strings.TrimPrefix(req.UnsignedMessage, "0x"), + strings.TrimPrefix(req.Message, "0x"), ) if err != nil { msg := "Could not decode message" logger.Warn( msg, - zap.String("msg", req.UnsignedMessage), + zap.String("msg", req.Message), zap.Error(err), ) writeJSONError(logger, w, msg) return } - unsignedMessage, err := types.UnpackWarpMessage(decodedMessage) + message, err := types.UnpackWarpMessage(decodedMessage) if err != nil { msg := "Error unpacking warp message" logger.Warn(msg, zap.Error(err)) writeJSONError(logger, w, msg) return } + + justification, err := hex.DecodeString( + utils.SanitizeHexString(req.Justification), + ) + if err != nil { + msg := "Could not decode justification" + logger.Warn( + msg, + zap.String("justification", req.Justification), + zap.Error(err), + ) + writeJSONError(logger, w, msg) + return + } + + if isEmptyOrZeroes(message.Bytes()) && isEmptyOrZeroes(justification) { + writeJSONError( + logger, + w, + "Must provide either message or justification", + ) + return + } + quorumPercentage := req.QuorumPercentage if quorumPercentage == 0 { quorumPercentage = DefaultQuorumPercentage @@ -140,7 +176,8 @@ func signatureAggregationAPIHandler( } signedMessage, err := aggregator.CreateSignedMessage( - unsignedMessage, + message, + justification, signingSubnetID, quorumPercentage, ) diff --git a/signature-aggregator/config/config.go b/signature-aggregator/config/config.go index 19b769d2..ec6d570e 100644 --- a/signature-aggregator/config/config.go +++ b/signature-aggregator/config/config.go @@ -5,6 +5,7 @@ package config import ( "fmt" + "time" "github.com/ava-labs/avalanchego/utils/logging" basecfg "github.com/ava-labs/awm-relayer/config" @@ -34,6 +35,9 @@ type Config struct { APIPort uint16 `mapstructure:"api-port" json:"api-port"` MetricsPort uint16 `mapstructure:"metrics-port" json:"metrics-port"` SignatureCacheSize uint64 `mapstructure:"signature-cache-size" json:"signature-cache-size"` + + // mapstructure doesn't support time.Time out of the box so handle it manually + EtnaTime time.Time `json:"etna-time"` } func DisplayUsageText() { diff --git a/signature-aggregator/config/keys.go b/signature-aggregator/config/keys.go index 97829f77..d2f3e077 100644 --- a/signature-aggregator/config/keys.go +++ b/signature-aggregator/config/keys.go @@ -16,4 +16,5 @@ const ( APIPortKey = "api-port" MetricsPortKey = "metrics-port" SignatureCacheSizeKey = "signature-cache-size" + EtnaTimeKey = "etna-time" ) diff --git a/signature-aggregator/config/viper.go b/signature-aggregator/config/viper.go index dc33f918..0ca4a410 100644 --- a/signature-aggregator/config/viper.go +++ b/signature-aggregator/config/viper.go @@ -76,5 +76,8 @@ func BuildConfig(v *viper.Viper) (Config, error) { return cfg, fmt.Errorf("failed to unmarshal viper config: %w", err) } + // mapstructure doesn't support time.Time out of the box so handle it manually + cfg.EtnaTime = v.GetTime(EtnaTimeKey) + return cfg, nil } diff --git a/signature-aggregator/main/main.go b/signature-aggregator/main/main.go index 69b619a1..27edfd3b 100644 --- a/signature-aggregator/main/main.go +++ b/signature-aggregator/main/main.go @@ -117,6 +117,7 @@ func main() { cfg.SignatureCacheSize, metricsInstance, messageCreator, + cfg.EtnaTime, ) if err != nil { logger.Fatal("Failed to create signature aggregator", zap.Error(err)) diff --git a/tests/e2e_test.go b/tests/e2e_test.go index 48a61808..4a475334 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -174,4 +174,7 @@ var _ = ginkgo.Describe("[AWM Relayer Integration Tests", func() { ginkgo.It("Signature Aggregator", func() { SignatureAggregatorAPI(localNetworkInstance) }) + ginkgo.It("Etna Upgrade", func() { + EtnaUpgrade(localNetworkInstance) + }) }) diff --git a/tests/etna_upgrade.go b/tests/etna_upgrade.go new file mode 100644 index 00000000..02ab768c --- /dev/null +++ b/tests/etna_upgrade.go @@ -0,0 +1,94 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package tests + +import ( + "context" + "time" + + testUtils "github.com/ava-labs/awm-relayer/tests/utils" + "github.com/ava-labs/teleporter/tests/interfaces" + "github.com/ava-labs/teleporter/tests/utils" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" + . "github.com/onsi/gomega" +) + +// This tests basic functionality of the relayer post-etna upgrade +// since other tests write zero value of time.Time +// to the config and therefore are testing the pre-etna case +// - Relaying from Subnet A to Subnet B +// - Relaying from Subnet B to Subnet A +func EtnaUpgrade(network interfaces.LocalNetwork) { + subnetAInfo := network.GetPrimaryNetworkInfo() + subnetBInfo, _ := utils.GetTwoSubnets(network) + fundedAddress, fundedKey := network.GetFundedAccountInfo() + teleporterContractAddress := network.GetTeleporterContractAddress() + err := testUtils.ClearRelayerStorage() + Expect(err).Should(BeNil()) + // + // Fund the relayer address on all subnets + // + ctx := context.Background() + + log.Info("Funding relayer address on all subnets") + relayerKey, err := crypto.GenerateKey() + Expect(err).Should(BeNil()) + testUtils.FundRelayers(ctx, []interfaces.SubnetTestInfo{subnetAInfo, subnetBInfo}, fundedKey, relayerKey) + + // + // Set up relayer config + // + relayerConfig := testUtils.CreateDefaultRelayerConfig( + []interfaces.SubnetTestInfo{subnetAInfo, subnetBInfo}, + []interfaces.SubnetTestInfo{subnetAInfo, subnetBInfo}, + teleporterContractAddress, + fundedAddress, + relayerKey, + ) + // Setting the EtnaTime to yesterday so that the post-etna logic path is used. + relayerConfig.EtnaTime = time.Now().AddDate(0, 0, -1) + // The config needs to be validated in order to be passed to database.GetConfigRelayerIDs + relayerConfig.Validate() + + relayerConfigPath := testUtils.WriteRelayerConfig(relayerConfig, testUtils.DefaultRelayerCfgFname) + + // + // Test Relaying from Subnet A to Subnet B + // + log.Info("Test Relaying from Subnet A to Subnet B") + + log.Info("Starting the relayer") + relayerCleanup, readyChan := testUtils.RunRelayerExecutable( + ctx, + relayerConfigPath, + relayerConfig, + ) + defer relayerCleanup() + + // Wait for relayer to start up + startupCtx, startupCancel := context.WithTimeout(ctx, 15*time.Second) + defer startupCancel() + testUtils.WaitForChannelClose(startupCtx, readyChan) + + log.Info("Sending transaction from Subnet A to Subnet B") + testUtils.RelayBasicMessage( + ctx, + subnetAInfo, + subnetBInfo, + teleporterContractAddress, + fundedKey, + fundedAddress, + ) + + log.Info("Test Relaying from Subnet B to Subnet A") + testUtils.RelayBasicMessage( + ctx, + subnetBInfo, + subnetAInfo, + teleporterContractAddress, + fundedKey, + fundedAddress, + ) +} diff --git a/tests/signature_aggregator_api.go b/tests/signature_aggregator_api.go index 4b00c23d..2e26855e 100644 --- a/tests/signature_aggregator_api.go +++ b/tests/signature_aggregator_api.go @@ -79,7 +79,7 @@ func SignatureAggregatorAPI(network interfaces.LocalNetwork) { warpMessage := getWarpMessageFromLog(ctx, receipt, subnetAInfo) reqBody := api.AggregateSignatureRequest{ - UnsignedMessage: "0x" + hex.EncodeToString(warpMessage.Bytes()), + Message: "0x" + hex.EncodeToString(warpMessage.Bytes()), } client := http.Client{