From e6219a2c365b5d4918e4f00346d6e209837414b8 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Thu, 19 Jan 2023 15:02:30 -0800 Subject: [PATCH 01/50] base warp backend --- plugin/evm/warp_backend.go | 66 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 plugin/evm/warp_backend.go diff --git a/plugin/evm/warp_backend.go b/plugin/evm/warp_backend.go new file mode 100644 index 0000000000..c59d3200db --- /dev/null +++ b/plugin/evm/warp_backend.go @@ -0,0 +1,66 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package evm + +import ( + "context" + "fmt" + + "github.com/ava-labs/avalanchego/snow" + + "github.com/ava-labs/avalanchego/database/prefixdb" + "github.com/ava-labs/avalanchego/database/versiondb" + + "github.com/ava-labs/avalanchego/database" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/vms/platformvm/teleporter" +) + +var ( + _ WarpBackend = &WarpMessagesDB{} + + dbPrefix = []byte("warp_messages") +) + +type WarpBackend interface { + AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error + GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) +} + +type WarpMessagesDB struct { + database.Database + snowCtx *snow.Context +} + +func NewWarpMessagesDB(snowCtx *snow.Context, vmDB *versiondb.Database) *WarpMessagesDB { + return &WarpMessagesDB{ + Database: prefixdb.New(dbPrefix, vmDB), + snowCtx: snowCtx, + } +} + +func (w *WarpMessagesDB) AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error { + messageHash, err := ids.ToID(unsignedMessage.Bytes()) + if err != nil { + return fmt.Errorf("failed to add message with key %s to warp database, err: %e", messageHash.String(), err) + } + + w.Put(messageHash[:], unsignedMessage.Bytes()) + return nil +} + +func (w *WarpMessagesDB) GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) { + messageBytes, err := w.Get(messageHash[:]) + if err != nil { + return nil, err + } + + unsignedMessage, err := teleporter.ParseUnsignedMessage(messageBytes) + if err != nil { + return nil, err + } + + return w.snowCtx.TeleporterSigner.Sign(unsignedMessage) +} From b054615c472f336b391fbbc8318873b4875e19b4 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Thu, 19 Jan 2023 15:10:48 -0800 Subject: [PATCH 02/50] add signature caching --- plugin/evm/warp_backend.go | 61 +++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/plugin/evm/warp_backend.go b/plugin/evm/warp_backend.go index c59d3200db..41872fa65d 100644 --- a/plugin/evm/warp_backend.go +++ b/plugin/evm/warp_backend.go @@ -7,15 +7,13 @@ import ( "context" "fmt" - "github.com/ava-labs/avalanchego/snow" - + "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/database/prefixdb" "github.com/ava-labs/avalanchego/database/versiondb" - - "github.com/ava-labs/avalanchego/database" - "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/vms/platformvm/teleporter" + lru "github.com/hashicorp/golang-lru" ) var ( @@ -24,6 +22,10 @@ var ( dbPrefix = []byte("warp_messages") ) +const ( + signatureCacheSize = 500 +) + type WarpBackend interface { AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) @@ -31,14 +33,23 @@ type WarpBackend interface { type WarpMessagesDB struct { database.Database - snowCtx *snow.Context + snowCtx *snow.Context + signatureCache *lru.Cache } -func NewWarpMessagesDB(snowCtx *snow.Context, vmDB *versiondb.Database) *WarpMessagesDB { - return &WarpMessagesDB{ - Database: prefixdb.New(dbPrefix, vmDB), - snowCtx: snowCtx, +func NewWarpMessagesDB(snowCtx *snow.Context, vmDB *versiondb.Database) (*WarpMessagesDB, error) { + signatureCache, err := lru.New(signatureCacheSize) + if err != nil { + return nil, err } + + db := &WarpMessagesDB{ + Database: prefixdb.New(dbPrefix, vmDB), + snowCtx: snowCtx, + signatureCache: signatureCache, + } + + return db, nil } func (w *WarpMessagesDB) AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error { @@ -52,15 +63,25 @@ func (w *WarpMessagesDB) AddMessage(ctx context.Context, unsignedMessage *telepo } func (w *WarpMessagesDB) GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) { - messageBytes, err := w.Get(messageHash[:]) - if err != nil { - return nil, err + if sig, ok := w.signatureCache.Get(messageHash[:]); ok { + return sig.([]byte), nil + } else { + messageBytes, err := w.Get(messageHash[:]) + if err != nil { + return nil, err + } + + unsignedMessage, err := teleporter.ParseUnsignedMessage(messageBytes) + if err != nil { + return nil, err + } + + signature, err := w.snowCtx.TeleporterSigner.Sign(unsignedMessage) + if err != nil { + return nil, err + } + + w.signatureCache.Add(messageHash[:], signature) + return signature, nil } - - unsignedMessage, err := teleporter.ParseUnsignedMessage(messageBytes) - if err != nil { - return nil, err - } - - return w.snowCtx.TeleporterSigner.Sign(unsignedMessage) } From 183a5cd66b31c377e739ad5ad84375a25682cf6a Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Thu, 19 Jan 2023 17:02:38 -0800 Subject: [PATCH 03/50] add docs --- plugin/evm/warp_backend.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugin/evm/warp_backend.go b/plugin/evm/warp_backend.go index 41872fa65d..0281ba821e 100644 --- a/plugin/evm/warp_backend.go +++ b/plugin/evm/warp_backend.go @@ -26,17 +26,24 @@ const ( signatureCacheSize = 500 ) +// WarpBackend keeps track of messages that are accepted by the warp precompiles and add them into a database. +// The backend is also used to query for warp message signatures by the signature request handler. type WarpBackend interface { + // AddMessage is called in the precompile OnAccept, to add warp messages into the database. AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error + + // GetSignature returns the signature of the requested message hash. GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) } +// WarpMessagesDB implements WarpBackend, keeping track of warp messages, and generating message signatures. type WarpMessagesDB struct { database.Database snowCtx *snow.Context signatureCache *lru.Cache } +// NewWarpMessagesDB creates a new WarpMessagesDB, and initializes the signature cache and message tracking database. func NewWarpMessagesDB(snowCtx *snow.Context, vmDB *versiondb.Database) (*WarpMessagesDB, error) { signatureCache, err := lru.New(signatureCacheSize) if err != nil { From 6043c137caf8a11589e542b196f0af75c36bc8c9 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Fri, 20 Jan 2023 11:25:30 -0800 Subject: [PATCH 04/50] error handling --- plugin/evm/warp_backend.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugin/evm/warp_backend.go b/plugin/evm/warp_backend.go index 0281ba821e..e6edb454f6 100644 --- a/plugin/evm/warp_backend.go +++ b/plugin/evm/warp_backend.go @@ -62,7 +62,7 @@ func NewWarpMessagesDB(snowCtx *snow.Context, vmDB *versiondb.Database) (*WarpMe func (w *WarpMessagesDB) AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error { messageHash, err := ids.ToID(unsignedMessage.Bytes()) if err != nil { - return fmt.Errorf("failed to add message with key %s to warp database, err: %e", messageHash.String(), err) + return fmt.Errorf("failed to add message with key %s to warp database: %w", messageHash.String(), err) } w.Put(messageHash[:], unsignedMessage.Bytes()) @@ -75,17 +75,17 @@ func (w *WarpMessagesDB) GetSignature(ctx context.Context, messageHash ids.ID) ( } else { messageBytes, err := w.Get(messageHash[:]) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to get warp message %s from db: %w", messageHash.String(), err) } unsignedMessage, err := teleporter.ParseUnsignedMessage(messageBytes) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to parse warp message %s: %w", messageHash.String(), err) } signature, err := w.snowCtx.TeleporterSigner.Sign(unsignedMessage) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to sign warp message %s: %w", messageHash.String(), err) } w.signatureCache.Add(messageHash[:], signature) From 24fe40e616acad3ba66f3c8ce58a829e552000ab Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Fri, 20 Jan 2023 13:58:38 -0800 Subject: [PATCH 05/50] pr fixes --- plugin/evm/warp_backend.go | 39 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/plugin/evm/warp_backend.go b/plugin/evm/warp_backend.go index e6edb454f6..2fb043a48a 100644 --- a/plugin/evm/warp_backend.go +++ b/plugin/evm/warp_backend.go @@ -65,30 +65,29 @@ func (w *WarpMessagesDB) AddMessage(ctx context.Context, unsignedMessage *telepo return fmt.Errorf("failed to add message with key %s to warp database: %w", messageHash.String(), err) } - w.Put(messageHash[:], unsignedMessage.Bytes()) - return nil + return w.Put(messageHash[:], unsignedMessage.Bytes()) } func (w *WarpMessagesDB) GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) { if sig, ok := w.signatureCache.Get(messageHash[:]); ok { return sig.([]byte), nil - } else { - messageBytes, err := w.Get(messageHash[:]) - if err != nil { - return nil, fmt.Errorf("failed to get warp message %s from db: %w", messageHash.String(), err) - } - - unsignedMessage, err := teleporter.ParseUnsignedMessage(messageBytes) - if err != nil { - return nil, fmt.Errorf("failed to parse warp message %s: %w", messageHash.String(), err) - } - - signature, err := w.snowCtx.TeleporterSigner.Sign(unsignedMessage) - if err != nil { - return nil, fmt.Errorf("failed to sign warp message %s: %w", messageHash.String(), err) - } - - w.signatureCache.Add(messageHash[:], signature) - return signature, nil } + + messageBytes, err := w.Get(messageHash[:]) + if err != nil { + return nil, fmt.Errorf("failed to get warp message %s from db: %w", messageHash.String(), err) + } + + unsignedMessage, err := teleporter.ParseUnsignedMessage(messageBytes) + if err != nil { + return nil, fmt.Errorf("failed to parse warp message %s: %w", messageHash.String(), err) + } + + signature, err := w.snowCtx.TeleporterSigner.Sign(unsignedMessage) + if err != nil { + return nil, fmt.Errorf("failed to sign warp message %s: %w", messageHash.String(), err) + } + + w.signatureCache.Add(messageHash[:], signature) + return signature, nil } From dc3e441893d89022de3d952126163304b1b135a7 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Fri, 20 Jan 2023 14:18:37 -0800 Subject: [PATCH 06/50] basic signature request --- plugin/evm/message/signature_request.go | 33 +++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 plugin/evm/message/signature_request.go diff --git a/plugin/evm/message/signature_request.go b/plugin/evm/message/signature_request.go new file mode 100644 index 0000000000..6186ac1c8a --- /dev/null +++ b/plugin/evm/message/signature_request.go @@ -0,0 +1,33 @@ +// (c) 2022, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package message + +import ( + "context" + + "github.com/ava-labs/avalanchego/utils/crypto/bls" + + "github.com/ava-labs/avalanchego/ids" +) + +var _ Request = SignatureRequest{} + +// SignatureRequest is a request for the BLS signature for the Teleporter message identified by the MessageID/DestinationChainID pair +type SignatureRequest struct { + UnsignedMessageID ids.ID `serialize:"true"` +} + +func (s SignatureRequest) String() string { + //TODO implement me + panic("implement me") +} + +func (s SignatureRequest) Handle(ctx context.Context, nodeID ids.NodeID, requestID uint32, handler RequestHandler) ([]byte, error) { + //TODO implement me + panic("implement me") +} + +type SignatureResponse struct { + Signature [bls.SignatureLen]byte `serialize:"true"` +} From 7820ec110b46c57d982453abd54099184e0b18d8 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Fri, 20 Jan 2023 14:21:32 -0800 Subject: [PATCH 07/50] hash unsigned message for key --- plugin/evm/warp_backend.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugin/evm/warp_backend.go b/plugin/evm/warp_backend.go index 2fb043a48a..5cd816567a 100644 --- a/plugin/evm/warp_backend.go +++ b/plugin/evm/warp_backend.go @@ -7,6 +7,8 @@ import ( "context" "fmt" + "github.com/ava-labs/avalanchego/utils/hashing" + "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/database/prefixdb" "github.com/ava-labs/avalanchego/database/versiondb" @@ -60,7 +62,8 @@ func NewWarpMessagesDB(snowCtx *snow.Context, vmDB *versiondb.Database) (*WarpMe } func (w *WarpMessagesDB) AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error { - messageHash, err := ids.ToID(unsignedMessage.Bytes()) + messageHashBytes := hashing.ComputeHash256(unsignedMessage.Bytes()) + messageHash, err := ids.ToID(messageHashBytes) if err != nil { return fmt.Errorf("failed to add message with key %s to warp database: %w", messageHash.String(), err) } From ff4d54dd215d24a602066a48a1f7efd2286c66da Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Fri, 20 Jan 2023 14:30:24 -0800 Subject: [PATCH 08/50] implement new Request and RequestHandler interfaces --- plugin/evm/message/codec.go | 4 ++++ plugin/evm/message/handler.go | 5 +++++ plugin/evm/message/signature_request.go | 11 +++++------ sync/handlers/handler.go | 4 ++++ 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/plugin/evm/message/codec.go b/plugin/evm/message/codec.go index 8b0fabd550..654e84094e 100644 --- a/plugin/evm/message/codec.go +++ b/plugin/evm/message/codec.go @@ -37,6 +37,10 @@ func init() { c.RegisterType(CodeRequest{}), c.RegisterType(CodeResponse{}), + // Warp request types + c.RegisterType(SignatureRequest{}), + c.RegisterType(SignatureResponse{}), + Codec.RegisterCodec(Version, c), ) diff --git a/plugin/evm/message/handler.go b/plugin/evm/message/handler.go index 4b7bf7c4d7..59c85906fa 100644 --- a/plugin/evm/message/handler.go +++ b/plugin/evm/message/handler.go @@ -37,6 +37,7 @@ type RequestHandler interface { HandleTrieLeafsRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, leafsRequest LeafsRequest) ([]byte, error) HandleBlockRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, request BlockRequest) ([]byte, error) HandleCodeRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, codeRequest CodeRequest) ([]byte, error) + HandleSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest SignatureRequest) ([]byte, error) } // ResponseHandler handles response for a sent request @@ -61,3 +62,7 @@ func (NoopRequestHandler) HandleBlockRequest(ctx context.Context, nodeID ids.Nod func (NoopRequestHandler) HandleCodeRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, codeRequest CodeRequest) ([]byte, error) { return nil, nil } + +func (NoopRequestHandler) HandleSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest SignatureRequest) ([]byte, error) { + return nil, nil +} diff --git a/plugin/evm/message/signature_request.go b/plugin/evm/message/signature_request.go index 6186ac1c8a..98b52e6294 100644 --- a/plugin/evm/message/signature_request.go +++ b/plugin/evm/message/signature_request.go @@ -5,6 +5,7 @@ package message import ( "context" + "fmt" "github.com/ava-labs/avalanchego/utils/crypto/bls" @@ -13,19 +14,17 @@ import ( var _ Request = SignatureRequest{} -// SignatureRequest is a request for the BLS signature for the Teleporter message identified by the MessageID/DestinationChainID pair +// SignatureRequest is used to request a warp message's signature. type SignatureRequest struct { - UnsignedMessageID ids.ID `serialize:"true"` + MessageID ids.ID `serialize:"true"` } func (s SignatureRequest) String() string { - //TODO implement me - panic("implement me") + return fmt.Sprintf("SignatureRequest(MessageID=%s)", s.MessageID.String()) } func (s SignatureRequest) Handle(ctx context.Context, nodeID ids.NodeID, requestID uint32, handler RequestHandler) ([]byte, error) { - //TODO implement me - panic("implement me") + return handler.HandleSignatureRequest(ctx, nodeID, requestID, s) } type SignatureResponse struct { diff --git a/sync/handlers/handler.go b/sync/handlers/handler.go index 5c0389cf40..c836e9b320 100644 --- a/sync/handlers/handler.go +++ b/sync/handlers/handler.go @@ -62,3 +62,7 @@ func (s *syncHandler) HandleBlockRequest(ctx context.Context, nodeID ids.NodeID, func (s *syncHandler) HandleCodeRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, codeRequest message.CodeRequest) ([]byte, error) { return s.codeRequestHandler.OnCodeRequest(ctx, nodeID, requestID, codeRequest) } + +func (s *syncHandler) HandleSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) { + return nil, nil +} From 4f0403e882eee7841501406e7213e82e7f8e9a8e Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Fri, 20 Jan 2023 14:40:49 -0800 Subject: [PATCH 09/50] signature handler impl without constructing one --- plugin/evm/message/codec.go | 2 +- plugin/evm/message/signature_request.go | 3 +-- sync/handlers/handler.go | 6 +++++- sync/handlers/signature_request.go | 26 +++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 sync/handlers/signature_request.go diff --git a/plugin/evm/message/codec.go b/plugin/evm/message/codec.go index 654e84094e..d58e292f41 100644 --- a/plugin/evm/message/codec.go +++ b/plugin/evm/message/codec.go @@ -4,9 +4,9 @@ package message import ( + "github.com/alecthomas/units" "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/codec/linearcodec" - "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/utils/wrappers" ) diff --git a/plugin/evm/message/signature_request.go b/plugin/evm/message/signature_request.go index 98b52e6294..1cfe5bfabd 100644 --- a/plugin/evm/message/signature_request.go +++ b/plugin/evm/message/signature_request.go @@ -7,9 +7,8 @@ import ( "context" "fmt" - "github.com/ava-labs/avalanchego/utils/crypto/bls" - "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/crypto/bls" ) var _ Request = SignatureRequest{} diff --git a/sync/handlers/handler.go b/sync/handlers/handler.go index c836e9b320..73b5ec1e5a 100644 --- a/sync/handlers/handler.go +++ b/sync/handlers/handler.go @@ -35,6 +35,7 @@ type syncHandler struct { stateTrieLeafsRequestHandler *LeafsRequestHandler blockRequestHandler *BlockRequestHandler codeRequestHandler *CodeRequestHandler + signatureRequestHandler *SignatureRequestHandler } // NewSyncHandler constructs the handler for serving state sync. @@ -48,6 +49,9 @@ func NewSyncHandler( stateTrieLeafsRequestHandler: NewLeafsRequestHandler(evmTrieDB, provider, networkCodec, stats), blockRequestHandler: NewBlockRequestHandler(provider, networkCodec, stats), codeRequestHandler: NewCodeRequestHandler(evmTrieDB.DiskDB(), networkCodec, stats), + + // TODO: need to pass in the warp backend from the subnet-evm. + signatureRequestHandler: NewSignatureRequestHandler(nil), } } @@ -64,5 +68,5 @@ func (s *syncHandler) HandleCodeRequest(ctx context.Context, nodeID ids.NodeID, } func (s *syncHandler) HandleSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) { - return nil, nil + return s.signatureRequestHandler.OnSignatureRequest(ctx, nodeID, requestID, signatureRequest) } diff --git a/sync/handlers/signature_request.go b/sync/handlers/signature_request.go new file mode 100644 index 0000000000..3d9f0b25f8 --- /dev/null +++ b/sync/handlers/signature_request.go @@ -0,0 +1,26 @@ +// (c) 2022, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package handlers + +import ( + "context" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/subnet-evm/plugin/evm" + "github.com/ava-labs/subnet-evm/plugin/evm/message" +) + +type SignatureRequestHandler struct { + backend evm.WarpBackend +} + +func NewSignatureRequestHandler(backend evm.WarpBackend) *SignatureRequestHandler { + return &SignatureRequestHandler{ + backend: backend, + } +} + +func (s *SignatureRequestHandler) OnSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) { + return s.backend.GetSignature(ctx, signatureRequest.MessageID) +} From c72904049a10a70050f07c9827517cd56ec8c400 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Fri, 20 Jan 2023 14:42:45 -0800 Subject: [PATCH 10/50] fix import --- plugin/evm/message/codec.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/evm/message/codec.go b/plugin/evm/message/codec.go index d58e292f41..654e84094e 100644 --- a/plugin/evm/message/codec.go +++ b/plugin/evm/message/codec.go @@ -4,9 +4,9 @@ package message import ( - "github.com/alecthomas/units" "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/codec/linearcodec" + "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/utils/wrappers" ) From 738d19e79db9ac2a8ebeb83036c3f39028788975 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Mon, 23 Jan 2023 09:34:43 -0800 Subject: [PATCH 11/50] quick pr fixes and merge --- plugin/evm/warp_backend.go | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/plugin/evm/warp_backend.go b/plugin/evm/warp_backend.go index 5cd816567a..a76e9746f0 100644 --- a/plugin/evm/warp_backend.go +++ b/plugin/evm/warp_backend.go @@ -19,15 +19,11 @@ import ( ) var ( - _ WarpBackend = &WarpMessagesDB{} + _ WarpBackend = &warpMessagesDB{} dbPrefix = []byte("warp_messages") ) -const ( - signatureCacheSize = 500 -) - // WarpBackend keeps track of messages that are accepted by the warp precompiles and add them into a database. // The backend is also used to query for warp message signatures by the signature request handler. type WarpBackend interface { @@ -38,21 +34,21 @@ type WarpBackend interface { GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) } -// WarpMessagesDB implements WarpBackend, keeping track of warp messages, and generating message signatures. -type WarpMessagesDB struct { +// warpMessagesDB implements WarpBackend, keeping track of warp messages, and generating message signatures. +type warpMessagesDB struct { database.Database snowCtx *snow.Context signatureCache *lru.Cache } -// NewWarpMessagesDB creates a new WarpMessagesDB, and initializes the signature cache and message tracking database. -func NewWarpMessagesDB(snowCtx *snow.Context, vmDB *versiondb.Database) (*WarpMessagesDB, error) { +// NewWarpMessagesDB creates a new warpMessagesDB, and initializes the signature cache and message tracking database. +func NewWarpMessagesDB(snowCtx *snow.Context, vmDB *versiondb.Database, signatureCacheSize int) (WarpBackend, error) { signatureCache, err := lru.New(signatureCacheSize) if err != nil { return nil, err } - db := &WarpMessagesDB{ + db := &warpMessagesDB{ Database: prefixdb.New(dbPrefix, vmDB), snowCtx: snowCtx, signatureCache: signatureCache, @@ -61,17 +57,17 @@ func NewWarpMessagesDB(snowCtx *snow.Context, vmDB *versiondb.Database) (*WarpMe return db, nil } -func (w *WarpMessagesDB) AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error { +func (w *warpMessagesDB) AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error { messageHashBytes := hashing.ComputeHash256(unsignedMessage.Bytes()) messageHash, err := ids.ToID(messageHashBytes) if err != nil { - return fmt.Errorf("failed to add message with key %s to warp database: %w", messageHash.String(), err) + return fmt.Errorf("failed to generate message hash for warp message database: %w", err) } return w.Put(messageHash[:], unsignedMessage.Bytes()) } -func (w *WarpMessagesDB) GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) { +func (w *warpMessagesDB) GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) { if sig, ok := w.signatureCache.Get(messageHash[:]); ok { return sig.([]byte), nil } From 8d333455f93dd32d7d19380677e5dc34add4c005 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Mon, 23 Jan 2023 09:34:43 -0800 Subject: [PATCH 12/50] quick pr fixes and merge --- plugin/evm/warp_backend.go | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/plugin/evm/warp_backend.go b/plugin/evm/warp_backend.go index 5cd816567a..a76e9746f0 100644 --- a/plugin/evm/warp_backend.go +++ b/plugin/evm/warp_backend.go @@ -19,15 +19,11 @@ import ( ) var ( - _ WarpBackend = &WarpMessagesDB{} + _ WarpBackend = &warpMessagesDB{} dbPrefix = []byte("warp_messages") ) -const ( - signatureCacheSize = 500 -) - // WarpBackend keeps track of messages that are accepted by the warp precompiles and add them into a database. // The backend is also used to query for warp message signatures by the signature request handler. type WarpBackend interface { @@ -38,21 +34,21 @@ type WarpBackend interface { GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) } -// WarpMessagesDB implements WarpBackend, keeping track of warp messages, and generating message signatures. -type WarpMessagesDB struct { +// warpMessagesDB implements WarpBackend, keeping track of warp messages, and generating message signatures. +type warpMessagesDB struct { database.Database snowCtx *snow.Context signatureCache *lru.Cache } -// NewWarpMessagesDB creates a new WarpMessagesDB, and initializes the signature cache and message tracking database. -func NewWarpMessagesDB(snowCtx *snow.Context, vmDB *versiondb.Database) (*WarpMessagesDB, error) { +// NewWarpMessagesDB creates a new warpMessagesDB, and initializes the signature cache and message tracking database. +func NewWarpMessagesDB(snowCtx *snow.Context, vmDB *versiondb.Database, signatureCacheSize int) (WarpBackend, error) { signatureCache, err := lru.New(signatureCacheSize) if err != nil { return nil, err } - db := &WarpMessagesDB{ + db := &warpMessagesDB{ Database: prefixdb.New(dbPrefix, vmDB), snowCtx: snowCtx, signatureCache: signatureCache, @@ -61,17 +57,17 @@ func NewWarpMessagesDB(snowCtx *snow.Context, vmDB *versiondb.Database) (*WarpMe return db, nil } -func (w *WarpMessagesDB) AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error { +func (w *warpMessagesDB) AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error { messageHashBytes := hashing.ComputeHash256(unsignedMessage.Bytes()) messageHash, err := ids.ToID(messageHashBytes) if err != nil { - return fmt.Errorf("failed to add message with key %s to warp database: %w", messageHash.String(), err) + return fmt.Errorf("failed to generate message hash for warp message database: %w", err) } return w.Put(messageHash[:], unsignedMessage.Bytes()) } -func (w *WarpMessagesDB) GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) { +func (w *warpMessagesDB) GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) { if sig, ok := w.signatureCache.Get(messageHash[:]); ok { return sig.([]byte), nil } From e8ac6706ab7fae824ae7d966b44cfeee444f9b8e Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Mon, 23 Jan 2023 11:15:26 -0800 Subject: [PATCH 13/50] save signature instead of whole msg --- plugin/evm/warp_backend.go | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/plugin/evm/warp_backend.go b/plugin/evm/warp_backend.go index a76e9746f0..b81c756429 100644 --- a/plugin/evm/warp_backend.go +++ b/plugin/evm/warp_backend.go @@ -61,10 +61,15 @@ func (w *warpMessagesDB) AddMessage(ctx context.Context, unsignedMessage *telepo messageHashBytes := hashing.ComputeHash256(unsignedMessage.Bytes()) messageHash, err := ids.ToID(messageHashBytes) if err != nil { - return fmt.Errorf("failed to generate message hash for warp message database: %w", err) + return fmt.Errorf("failed to generate message hash for warp message db: %w", err) } - return w.Put(messageHash[:], unsignedMessage.Bytes()) + signature, err := w.snowCtx.TeleporterSigner.Sign(unsignedMessage) + if err != nil { + return fmt.Errorf("failed to sign warp message %s: %w", messageHash.String(), err) + } + + return w.Put(messageHash[:], signature) } func (w *warpMessagesDB) GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) { @@ -72,19 +77,9 @@ func (w *warpMessagesDB) GetSignature(ctx context.Context, messageHash ids.ID) ( return sig.([]byte), nil } - messageBytes, err := w.Get(messageHash[:]) - if err != nil { - return nil, fmt.Errorf("failed to get warp message %s from db: %w", messageHash.String(), err) - } - - unsignedMessage, err := teleporter.ParseUnsignedMessage(messageBytes) - if err != nil { - return nil, fmt.Errorf("failed to parse warp message %s: %w", messageHash.String(), err) - } - - signature, err := w.snowCtx.TeleporterSigner.Sign(unsignedMessage) + signature, err := w.Get(messageHash[:]) if err != nil { - return nil, fmt.Errorf("failed to sign warp message %s: %w", messageHash.String(), err) + return nil, fmt.Errorf("failed to get warp signature for message %s from db: %w", messageHash.String(), err) } w.signatureCache.Add(messageHash[:], signature) From bd75e6d25c4e0aa98151829ce6e3624c3e7e345e Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Mon, 23 Jan 2023 11:20:52 -0800 Subject: [PATCH 14/50] use avaGO cache --- plugin/evm/warp_backend.go | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/plugin/evm/warp_backend.go b/plugin/evm/warp_backend.go index b81c756429..a420dc85cf 100644 --- a/plugin/evm/warp_backend.go +++ b/plugin/evm/warp_backend.go @@ -7,15 +7,14 @@ import ( "context" "fmt" - "github.com/ava-labs/avalanchego/utils/hashing" - + "github.com/ava-labs/avalanchego/cache" "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/database/prefixdb" "github.com/ava-labs/avalanchego/database/versiondb" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/vms/platformvm/teleporter" - lru "github.com/hashicorp/golang-lru" ) var ( @@ -38,23 +37,16 @@ type WarpBackend interface { type warpMessagesDB struct { database.Database snowCtx *snow.Context - signatureCache *lru.Cache + signatureCache *cache.LRU } // NewWarpMessagesDB creates a new warpMessagesDB, and initializes the signature cache and message tracking database. -func NewWarpMessagesDB(snowCtx *snow.Context, vmDB *versiondb.Database, signatureCacheSize int) (WarpBackend, error) { - signatureCache, err := lru.New(signatureCacheSize) - if err != nil { - return nil, err - } - - db := &warpMessagesDB{ +func NewWarpMessagesDB(snowCtx *snow.Context, vmDB *versiondb.Database, signatureCacheSize int) WarpBackend { + return &warpMessagesDB{ Database: prefixdb.New(dbPrefix, vmDB), snowCtx: snowCtx, - signatureCache: signatureCache, + signatureCache: &cache.LRU{Size: signatureCacheSize}, } - - return db, nil } func (w *warpMessagesDB) AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error { @@ -82,6 +74,6 @@ func (w *warpMessagesDB) GetSignature(ctx context.Context, messageHash ids.ID) ( return nil, fmt.Errorf("failed to get warp signature for message %s from db: %w", messageHash.String(), err) } - w.signatureCache.Add(messageHash[:], signature) + w.signatureCache.Put(messageHash[:], signature) return signature, nil } From 5d61bb0dd4ece76adbe2be2d5ad46c61a6a1e92a Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Mon, 23 Jan 2023 11:25:35 -0800 Subject: [PATCH 15/50] rename warpBackend and docs --- plugin/evm/warp_backend.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/plugin/evm/warp_backend.go b/plugin/evm/warp_backend.go index a420dc85cf..c8f61081a2 100644 --- a/plugin/evm/warp_backend.go +++ b/plugin/evm/warp_backend.go @@ -18,7 +18,7 @@ import ( ) var ( - _ WarpBackend = &warpMessagesDB{} + _ WarpBackend = &warpBackend{} dbPrefix = []byte("warp_messages") ) @@ -33,29 +33,31 @@ type WarpBackend interface { GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) } -// warpMessagesDB implements WarpBackend, keeping track of warp messages, and generating message signatures. -type warpMessagesDB struct { +// warpBackend implements WarpBackend, keeping track of warp messages, and generating message signatures. +type warpBackend struct { database.Database snowCtx *snow.Context signatureCache *cache.LRU } -// NewWarpMessagesDB creates a new warpMessagesDB, and initializes the signature cache and message tracking database. -func NewWarpMessagesDB(snowCtx *snow.Context, vmDB *versiondb.Database, signatureCacheSize int) WarpBackend { - return &warpMessagesDB{ +// NewWarpBackend creates a new warpBackend, and initializes the signature cache and message tracking database. +func NewWarpBackend(snowCtx *snow.Context, vmDB *versiondb.Database, signatureCacheSize int) WarpBackend { + return &warpBackend{ Database: prefixdb.New(dbPrefix, vmDB), snowCtx: snowCtx, signatureCache: &cache.LRU{Size: signatureCacheSize}, } } -func (w *warpMessagesDB) AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error { +func (w *warpBackend) AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error { messageHashBytes := hashing.ComputeHash256(unsignedMessage.Bytes()) messageHash, err := ids.ToID(messageHashBytes) if err != nil { return fmt.Errorf("failed to generate message hash for warp message db: %w", err) } + // We generate the signature here and only save the signature in the db. + // It is left to smart contracts built on top of Warp to save messages if required. signature, err := w.snowCtx.TeleporterSigner.Sign(unsignedMessage) if err != nil { return fmt.Errorf("failed to sign warp message %s: %w", messageHash.String(), err) @@ -64,7 +66,8 @@ func (w *warpMessagesDB) AddMessage(ctx context.Context, unsignedMessage *telepo return w.Put(messageHash[:], signature) } -func (w *warpMessagesDB) GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) { +func (w *warpBackend) GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) { + // Attempt to get the signature from cache before calling the db. if sig, ok := w.signatureCache.Get(messageHash[:]); ok { return sig.([]byte), nil } From 7b650b6aa44f134b97a5d9a41e16503717eacec9 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Mon, 23 Jan 2023 11:27:15 -0800 Subject: [PATCH 16/50] fix nits --- plugin/evm/warp_backend.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/evm/warp_backend.go b/plugin/evm/warp_backend.go index c8f61081a2..82bf15988c 100644 --- a/plugin/evm/warp_backend.go +++ b/plugin/evm/warp_backend.go @@ -20,7 +20,7 @@ import ( var ( _ WarpBackend = &warpBackend{} - dbPrefix = []byte("warp_messages") + dbPrefix = []byte("warp") ) // WarpBackend keeps track of messages that are accepted by the warp precompiles and add them into a database. @@ -33,7 +33,7 @@ type WarpBackend interface { GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) } -// warpBackend implements WarpBackend, keeping track of warp messages, and generating message signatures. +// warpBackend implements WarpBackend, keeps track of warp messages, and generates message signatures. type warpBackend struct { database.Database snowCtx *snow.Context From 887fd6f13ff098136fb46ad705e8766a6213375a Mon Sep 17 00:00:00 2001 From: minghinmatthewlam Date: Mon, 23 Jan 2023 13:32:51 -0800 Subject: [PATCH 17/50] Update plugin/evm/warp_backend.go Co-authored-by: aaronbuchwald --- plugin/evm/warp_backend.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/evm/warp_backend.go b/plugin/evm/warp_backend.go index 82bf15988c..c4fe046d3b 100644 --- a/plugin/evm/warp_backend.go +++ b/plugin/evm/warp_backend.go @@ -26,7 +26,7 @@ var ( // WarpBackend keeps track of messages that are accepted by the warp precompiles and add them into a database. // The backend is also used to query for warp message signatures by the signature request handler. type WarpBackend interface { - // AddMessage is called in the precompile OnAccept, to add warp messages into the database. + // AddMessage signs [unsignedMessage] and adds it to the warp backend database AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error // GetSignature returns the signature of the requested message hash. From 7c8e06fdec571179a0fc61f4c1644ae7dd02ef93 Mon Sep 17 00:00:00 2001 From: minghinmatthewlam Date: Mon, 23 Jan 2023 13:33:15 -0800 Subject: [PATCH 18/50] Update plugin/evm/warp_backend.go Co-authored-by: aaronbuchwald --- plugin/evm/warp_backend.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/evm/warp_backend.go b/plugin/evm/warp_backend.go index c4fe046d3b..10fdced581 100644 --- a/plugin/evm/warp_backend.go +++ b/plugin/evm/warp_backend.go @@ -23,7 +23,7 @@ var ( dbPrefix = []byte("warp") ) -// WarpBackend keeps track of messages that are accepted by the warp precompiles and add them into a database. +// WarpBackend 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 WarpBackend interface { // AddMessage signs [unsignedMessage] and adds it to the warp backend database From b0f2ff3c4cf3970bf0de5ee2dfb9346eeb80c3df Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Mon, 23 Jan 2023 13:35:00 -0800 Subject: [PATCH 19/50] fix pr nits --- .../evm/{warp_backend.go => warp/backend.go} | 46 ++++++++----------- 1 file changed, 20 insertions(+), 26 deletions(-) rename plugin/evm/{warp_backend.go => warp/backend.go} (61%) diff --git a/plugin/evm/warp_backend.go b/plugin/evm/warp/backend.go similarity index 61% rename from plugin/evm/warp_backend.go rename to plugin/evm/warp/backend.go index 10fdced581..12a3c3e95b 100644 --- a/plugin/evm/warp_backend.go +++ b/plugin/evm/warp/backend.go @@ -1,7 +1,7 @@ // (c) 2019-2020, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package evm +package warp import ( "context" @@ -9,19 +9,13 @@ import ( "github.com/ava-labs/avalanchego/cache" "github.com/ava-labs/avalanchego/database" - "github.com/ava-labs/avalanchego/database/prefixdb" - "github.com/ava-labs/avalanchego/database/versiondb" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/vms/platformvm/teleporter" ) -var ( - _ WarpBackend = &warpBackend{} - - dbPrefix = []byte("warp") -) +var _ WarpBackend = &warpBackend{} // WarpBackend 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. @@ -35,48 +29,48 @@ type WarpBackend interface { // warpBackend implements WarpBackend, keeps track of warp messages, and generates message signatures. type warpBackend struct { - database.Database + db database.Database snowCtx *snow.Context signatureCache *cache.LRU } -// NewWarpBackend creates a new warpBackend, and initializes the signature cache and message tracking database. -func NewWarpBackend(snowCtx *snow.Context, vmDB *versiondb.Database, signatureCacheSize int) WarpBackend { +// NewWarpBackend creates a new WarpBackend, and initializes the signature cache and message tracking database. +func NewWarpBackend(snowCtx *snow.Context, db database.Database, signatureCacheSize int) WarpBackend { return &warpBackend{ - Database: prefixdb.New(dbPrefix, vmDB), + db: db, snowCtx: snowCtx, signatureCache: &cache.LRU{Size: signatureCacheSize}, } } func (w *warpBackend) AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error { - messageHashBytes := hashing.ComputeHash256(unsignedMessage.Bytes()) - messageHash, err := ids.ToID(messageHashBytes) - if err != nil { - return fmt.Errorf("failed to generate message hash for warp message db: %w", err) - } + messageID := hashing.ComputeHash256Array(unsignedMessage.Bytes()) - // We generate the signature here and only save the signature in the db. + // We generate the signature here and only save the signature in the db and cache. // It is left to smart contracts built on top of Warp to save messages if required. signature, err := w.snowCtx.TeleporterSigner.Sign(unsignedMessage) if err != nil { - return fmt.Errorf("failed to sign warp message %s: %w", messageHash.String(), err) + return fmt.Errorf("failed to sign warp message: %w", err) + } + + if err := w.db.Put(messageID[:], signature); err != nil { + return fmt.Errorf("failed to put warp signature in db: %w", err) } - return w.Put(messageHash[:], signature) + w.signatureCache.Put(messageID[:], signature) + return nil } -func (w *warpBackend) GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) { - // Attempt to get the signature from cache before calling the db. - if sig, ok := w.signatureCache.Get(messageHash[:]); ok { +func (w *warpBackend) GetSignature(ctx context.Context, messageID ids.ID) ([]byte, error) { + if sig, ok := w.signatureCache.Get(messageID[:]); ok { return sig.([]byte), nil } - signature, err := w.Get(messageHash[:]) + signature, err := w.db.Get(messageID[:]) if err != nil { - return nil, fmt.Errorf("failed to get warp signature for message %s from db: %w", messageHash.String(), err) + return nil, fmt.Errorf("failed to get warp signature for message %s from db: %w", messageID.String(), err) } - w.signatureCache.Put(messageHash[:], signature) + w.signatureCache.Put(messageID[:], signature) return signature, nil } From 8fc39cdf61fba5d59204b63e0d57fc58b01c915f Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Mon, 23 Jan 2023 16:34:20 -0800 Subject: [PATCH 20/50] pr fixes and testing --- plugin/evm/warp/backend.go | 4 +- plugin/evm/warp/backend_test.go | 95 +++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 plugin/evm/warp/backend_test.go diff --git a/plugin/evm/warp/backend.go b/plugin/evm/warp/backend.go index 12a3c3e95b..e021ac0bbd 100644 --- a/plugin/evm/warp/backend.go +++ b/plugin/evm/warp/backend.go @@ -57,12 +57,12 @@ func (w *warpBackend) AddMessage(ctx context.Context, unsignedMessage *teleporte return fmt.Errorf("failed to put warp signature in db: %w", err) } - w.signatureCache.Put(messageID[:], signature) + w.signatureCache.Put(ids.ID(messageID), signature) return nil } func (w *warpBackend) GetSignature(ctx context.Context, messageID ids.ID) ([]byte, error) { - if sig, ok := w.signatureCache.Get(messageID[:]); ok { + if sig, ok := w.signatureCache.Get(messageID); ok { return sig.([]byte), nil } diff --git a/plugin/evm/warp/backend_test.go b/plugin/evm/warp/backend_test.go new file mode 100644 index 0000000000..99032feae7 --- /dev/null +++ b/plugin/evm/warp/backend_test.go @@ -0,0 +1,95 @@ +// (c) 2019-2021, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package warp + +import ( + "context" + "errors" + "reflect" + "testing" + + "github.com/ava-labs/avalanchego/utils/hashing" + + "github.com/ava-labs/avalanchego/utils/crypto/bls" + "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/database/mockdb" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/avalanchego/vms/platformvm/teleporter" +) + +var ( + sourceChainID = ids.GenerateTestID() + destinationChainID = ids.GenerateTestID() + payload = []byte("test") + + errTest = errors.New("non-nil error") +) + +func TestInterfaceStructOneToOne(t *testing.T) { + // checks struct provides at least the methods signatures in the interface + var _ WarpBackend = (*warpBackend)(nil) + // checks interface and struct have the same number of methods + backendType := reflect.TypeOf(&warpBackend{}) + BackendType := reflect.TypeOf((*WarpBackend)(nil)).Elem() + if backendType.NumMethod() != BackendType.NumMethod() { + t.Fatalf("no 1 to 1 compliance between struct methods (%v) and interface methods (%v)", backendType.NumMethod(), BackendType.NumMethod()) + } +} + +func TestWarpBackend_ValidMessage(t *testing.T) { + db := mockdb.New() + called := new(bool) + db.OnPut = func([]byte, []byte) error { + *called = true + return nil + } + + snowCtx := snow.DefaultContextTest() + snowCtx.TeleporterSigner = getTestSigner(t, sourceChainID) + be := NewWarpBackend(snowCtx, db, 500) + + // Create a new unsigned message and add it to the warp backend. + unsignedMsg, err := teleporter.NewUnsignedMessage(sourceChainID, destinationChainID, payload) + require.NoError(t, err) + err = be.AddMessage(context.Background(), unsignedMsg) + require.NoError(t, err) + require.True(t, *called) + + // Verify that a signature is returned successfully, and compare to expected signature. + messageID := hashing.ComputeHash256Array(unsignedMsg.Bytes()) + signature, err := be.GetSignature(context.Background(), messageID) + require.NoError(t, err) + + expectedSig, err := snowCtx.TeleporterSigner.Sign(unsignedMsg) + require.NoError(t, err) + require.Equal(t, expectedSig, signature) +} + +func TestWarpBackend_InvalidMessage(t *testing.T) { + db := mockdb.New() + called := new(bool) + db.OnGet = func([]byte) ([]byte, error) { + *called = true + return nil, errTest + } + + be := NewWarpBackend(snow.DefaultContextTest(), db, 500) + unsignedMsg, err := teleporter.NewUnsignedMessage(sourceChainID, destinationChainID, payload) + require.NoError(t, err) + + // Try getting a signature for a message that was not added. + messageID := hashing.ComputeHash256Array(unsignedMsg.Bytes()) + _, err = be.GetSignature(context.Background(), messageID) + require.Error(t, err) + require.True(t, *called) +} + +func getTestSigner(t *testing.T, sourceID ids.ID) teleporter.Signer { + sk, err := bls.NewSecretKey() + require.NoError(t, err) + + return teleporter.NewSigner(sk, sourceID) +} From 76a8a0e73c53dbac08af25057a6aa9d2c05536d2 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Mon, 23 Jan 2023 17:11:11 -0800 Subject: [PATCH 21/50] type check for caching --- plugin/evm/warp/backend_test.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/plugin/evm/warp/backend_test.go b/plugin/evm/warp/backend_test.go index 99032feae7..3f7f2aa77e 100644 --- a/plugin/evm/warp/backend_test.go +++ b/plugin/evm/warp/backend_test.go @@ -9,6 +9,8 @@ import ( "reflect" "testing" + "github.com/ava-labs/avalanchego/cache" + "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/utils/crypto/bls" @@ -87,6 +89,27 @@ func TestWarpBackend_InvalidMessage(t *testing.T) { require.True(t, *called) } +func TestCacheTypes(t *testing.T) { + var ( + key = []byte("key") + val = []byte("value") + ) + + hash := hashing.ComputeHash256Array(key) + cache := &cache.LRU{Size: 100} + + // First put into cache with key type Hash256, resulting in cache miss. + cache.Put(hash, val) + _, ok := cache.Get(ids.ID(hash)) + require.False(t, ok) + + // Put into cache with key type ids.ID, cache hit. + cache.Put(ids.ID(hash), val) + res, ok := cache.Get(ids.ID(hash)) + require.True(t, ok) + require.Equal(t, val, res) +} + func getTestSigner(t *testing.T, sourceID ids.ID) teleporter.Signer { sk, err := bls.NewSecretKey() require.NoError(t, err) From c745420d1c266416448ef5b4bb6d2fb66f9e62d0 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Tue, 24 Jan 2023 11:24:55 -0800 Subject: [PATCH 22/50] handlers and request before tests --- plugin/evm/message/signature_request.go | 2 ++ sync/handlers/handler.go | 2 +- sync/handlers/signature_request.go | 12 +++++++++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/plugin/evm/message/signature_request.go b/plugin/evm/message/signature_request.go index 1cfe5bfabd..c51be2449f 100644 --- a/plugin/evm/message/signature_request.go +++ b/plugin/evm/message/signature_request.go @@ -26,6 +26,8 @@ func (s SignatureRequest) Handle(ctx context.Context, nodeID ids.NodeID, request return handler.HandleSignatureRequest(ctx, nodeID, requestID, s) } +// SignatureResponse is the response to a SignatureRequest. +// The response contains a BLS signature of the requested message, signed by the responding node's BLS private key. type SignatureResponse struct { Signature [bls.SignatureLen]byte `serialize:"true"` } diff --git a/sync/handlers/handler.go b/sync/handlers/handler.go index 73b5ec1e5a..b26dc58783 100644 --- a/sync/handlers/handler.go +++ b/sync/handlers/handler.go @@ -51,7 +51,7 @@ func NewSyncHandler( codeRequestHandler: NewCodeRequestHandler(evmTrieDB.DiskDB(), networkCodec, stats), // TODO: need to pass in the warp backend from the subnet-evm. - signatureRequestHandler: NewSignatureRequestHandler(nil), + signatureRequestHandler: NewSignatureRequestHandler(nil, networkCodec), } } diff --git a/sync/handlers/signature_request.go b/sync/handlers/signature_request.go index 3d9f0b25f8..21ce878b60 100644 --- a/sync/handlers/signature_request.go +++ b/sync/handlers/signature_request.go @@ -6,21 +6,27 @@ package handlers import ( "context" + "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/subnet-evm/plugin/evm" "github.com/ava-labs/subnet-evm/plugin/evm/message" + "github.com/ava-labs/subnet-evm/plugin/evm/warp" ) +// SignatureRequestHandler is a peer.RequestHandler for message.SignatureRequest +// serving requested BLS signature data type SignatureRequestHandler struct { - backend evm.WarpBackend + backend warp.WarpBackend + codec codec.Manager } -func NewSignatureRequestHandler(backend evm.WarpBackend) *SignatureRequestHandler { +func NewSignatureRequestHandler(backend warp.WarpBackend, codec codec.Manager) *SignatureRequestHandler { return &SignatureRequestHandler{ backend: backend, + codec: codec, } } +// OnSignatureRequest handles message.SignatureRequest, and retrieves a warp signature for the requested message ID. func (s *SignatureRequestHandler) OnSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) { return s.backend.GetSignature(ctx, signatureRequest.MessageID) } From 17d11018be6ef968755f7d1687030cdca08ef7bc Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Tue, 24 Jan 2023 11:25:54 -0800 Subject: [PATCH 23/50] fix imports --- plugin/evm/warp/backend_test.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/plugin/evm/warp/backend_test.go b/plugin/evm/warp/backend_test.go index 3f7f2aa77e..b29f47e6c1 100644 --- a/plugin/evm/warp/backend_test.go +++ b/plugin/evm/warp/backend_test.go @@ -10,16 +10,13 @@ import ( "testing" "github.com/ava-labs/avalanchego/cache" - - "github.com/ava-labs/avalanchego/utils/hashing" - - "github.com/ava-labs/avalanchego/utils/crypto/bls" - "github.com/stretchr/testify/require" - "github.com/ava-labs/avalanchego/database/mockdb" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/avalanchego/utils/crypto/bls" + "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/vms/platformvm/teleporter" + "github.com/stretchr/testify/require" ) var ( From 4582f47eae9fb19fe62fda24ec5023f5d88a9e01 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Wed, 25 Jan 2023 14:37:23 -0800 Subject: [PATCH 24/50] signature handler with stats and test --- plugin/evm/message/signature_request_test.go | 63 +++++++++++++ sync/handlers/code_request_test.go | 2 +- sync/handlers/handler.go | 2 +- sync/handlers/signature_request.go | 42 ++++++++- sync/handlers/signature_request_test.go | 98 ++++++++++++++++++++ sync/handlers/stats/mock_stats.go | 33 +++++++ sync/handlers/stats/stats.go | 31 +++++++ 7 files changed, 267 insertions(+), 4 deletions(-) create mode 100644 plugin/evm/message/signature_request_test.go create mode 100644 sync/handlers/signature_request_test.go diff --git a/plugin/evm/message/signature_request_test.go b/plugin/evm/message/signature_request_test.go new file mode 100644 index 0000000000..647761138e --- /dev/null +++ b/plugin/evm/message/signature_request_test.go @@ -0,0 +1,63 @@ +// (c) 2022, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package message + +import ( + "encoding/base64" + "encoding/hex" + "testing" + + "github.com/ava-labs/avalanchego/ids" + + "github.com/ava-labs/avalanchego/utils/crypto/bls" + "github.com/stretchr/testify/require" +) + +// TestMarshalSignatureRequest asserts that the structure or serialization logic hasn't changed, primarily to +// ensure compatibility with the network. +func TestMarshalSignatureRequest(t *testing.T) { + messageIDBytes, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000") + require.NoError(t, err) + messageID, err := ids.ToID(messageIDBytes) + require.NoError(t, err) + + signatureRequest := SignatureRequest{ + MessageID: messageID, + } + + base64SignatureRequest := "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + signatureRequestBytes, err := Codec.Marshal(Version, signatureRequest) + require.NoError(t, err) + require.Equal(t, base64SignatureRequest, base64.StdEncoding.EncodeToString(signatureRequestBytes)) + + var s SignatureRequest + _, err = Codec.Unmarshal(signatureRequestBytes, &s) + require.NoError(t, err) + require.Equal(t, signatureRequest.MessageID, s.MessageID) +} + +// TestMarshalSignatureResponse asserts that the structure or serialization logic hasn't changed, primarily to +// ensure compatibility with the network. +func TestMarshalSignatureResponse(t *testing.T) { + var signature [bls.SignatureLen]byte + sig, err := hex.DecodeString("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef") + if err != nil { + t.Error("failed to decode string to hex") + } + + copy(signature[:], sig) + signatureResponse := SignatureResponse{ + Signature: signature, + } + + base64SignatureResponse := "AAABI0VniavN7wEjRWeJq83vASNFZ4mrze8BI0VniavN7wEjRWeJq83vASNFZ4mrze8BI0VniavN7wEjRWeJq83vASNFZ4mrze8BI0VniavN7wEjRWeJq83vASNFZ4mrze8=" + signatureResponseBytes, err := Codec.Marshal(Version, signatureResponse) + require.NoError(t, err) + require.Equal(t, base64SignatureResponse, base64.StdEncoding.EncodeToString(signatureResponseBytes)) + + var s SignatureResponse + _, err = Codec.Unmarshal(signatureResponseBytes, &s) + require.NoError(t, err) + require.Equal(t, signatureResponse.Signature, s.Signature) +} diff --git a/sync/handlers/code_request_test.go b/sync/handlers/code_request_test.go index cbf6b277bb..a7094742e1 100644 --- a/sync/handlers/code_request_test.go +++ b/sync/handlers/code_request_test.go @@ -94,7 +94,7 @@ func TestCodeRequestHandler(t *testing.T) { responseBytes, err := codeRequestHandler.OnCodeRequest(context.Background(), ids.GenerateTestNodeID(), 1, request) assert.NoError(t, err) - // If the expected resposne is empty, assert that the handler returns an empty response and return early. + // If the expected response is empty, assert that the handler returns an empty response and return early. if len(expectedResponse) == 0 { assert.Len(t, responseBytes, 0, "expected response to be empty") return diff --git a/sync/handlers/handler.go b/sync/handlers/handler.go index b26dc58783..b84a8d0686 100644 --- a/sync/handlers/handler.go +++ b/sync/handlers/handler.go @@ -51,7 +51,7 @@ func NewSyncHandler( codeRequestHandler: NewCodeRequestHandler(evmTrieDB.DiskDB(), networkCodec, stats), // TODO: need to pass in the warp backend from the subnet-evm. - signatureRequestHandler: NewSignatureRequestHandler(nil, networkCodec), + signatureRequestHandler: NewSignatureRequestHandler(nil, networkCodec, stats), } } diff --git a/sync/handlers/signature_request.go b/sync/handlers/signature_request.go index 21ce878b60..3106cbd73c 100644 --- a/sync/handlers/signature_request.go +++ b/sync/handlers/signature_request.go @@ -5,6 +5,13 @@ package handlers import ( "context" + "time" + + "github.com/ava-labs/subnet-evm/sync/handlers/stats" + + "github.com/ava-labs/avalanchego/utils/crypto/bls" + + "github.com/ethereum/go-ethereum/log" "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/ids" @@ -17,16 +24,47 @@ import ( type SignatureRequestHandler struct { backend warp.WarpBackend codec codec.Manager + stats stats.SignatureRequestHandlerStats } -func NewSignatureRequestHandler(backend warp.WarpBackend, codec codec.Manager) *SignatureRequestHandler { +func NewSignatureRequestHandler(backend warp.WarpBackend, codec codec.Manager, stats stats.SignatureRequestHandlerStats) *SignatureRequestHandler { return &SignatureRequestHandler{ backend: backend, codec: codec, + stats: stats, } } // OnSignatureRequest handles message.SignatureRequest, and retrieves a warp signature for the requested message ID. +// Never returns an error +// Expects returned errors to be treated as FATAL +// Returns empty response if signature is not found +// Assumes ctx is active func (s *SignatureRequestHandler) OnSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) { - return s.backend.GetSignature(ctx, signatureRequest.MessageID) + startTime := time.Now() + s.stats.IncSignatureRequest() + + // always report signature request time + defer func() { + s.stats.UpdateSignatureRequestTime(time.Since(startTime)) + }() + + var signature [bls.SignatureLen]byte + sig, err := s.backend.GetSignature(ctx, signatureRequest.MessageID) + if err != nil { + log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) + s.stats.IncSignatureMiss() + return nil, nil + } + + s.stats.IncSignatureHit() + copy(signature[:], sig) + response := message.SignatureResponse{Signature: signature} + responseBytes, err := s.codec.Marshal(message.Version, response) + if err != nil { + log.Warn("could not marshal SignatureResponse, dropping request", "nodeID", nodeID, "requestID", requestID, "err", err) + return nil, nil + } + + return responseBytes, nil } diff --git a/sync/handlers/signature_request_test.go b/sync/handlers/signature_request_test.go new file mode 100644 index 0000000000..61517844b7 --- /dev/null +++ b/sync/handlers/signature_request_test.go @@ -0,0 +1,98 @@ +// (c) 2021-2022, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package handlers + +import ( + "context" + "testing" + "time" + + "github.com/ava-labs/avalanchego/database/memdb" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/avalanchego/utils/crypto/bls" + "github.com/ava-labs/avalanchego/utils/hashing" + "github.com/ava-labs/avalanchego/vms/platformvm/teleporter" + "github.com/ava-labs/subnet-evm/plugin/evm/message" + "github.com/ava-labs/subnet-evm/plugin/evm/warp" + "github.com/ava-labs/subnet-evm/sync/handlers/stats" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSignatureHandler(t *testing.T) { + database := memdb.New() + snowCtx := snow.DefaultContextTest() + blsSecretKey, err := bls.NewSecretKey() + require.NoError(t, err) + + snowCtx.TeleporterSigner = teleporter.NewSigner(blsSecretKey, snowCtx.ChainID) + warpBackend := warp.NewWarpBackend(snowCtx, database, 100) + + msg, err := teleporter.NewUnsignedMessage(snowCtx.ChainID, snowCtx.CChainID, []byte("test")) + require.NoError(t, err) + + messageID := hashing.ComputeHash256Array(msg.Bytes()) + require.NoError(t, warpBackend.AddMessage(context.Background(), msg)) + signature, err := warpBackend.GetSignature(context.Background(), messageID) + require.NoError(t, err) + unknownMessageID := ids.GenerateTestID() + + mockHandlerStats := &stats.MockHandlerStats{} + signatureRequestHandler := NewSignatureRequestHandler(warpBackend, message.Codec, mockHandlerStats) + + tests := map[string]struct { + setup func() (request message.SignatureRequest, expectedResponse []byte) + verifyStats func(t *testing.T, stats *stats.MockHandlerStats) + }{ + "normal": { + setup: func() (request message.SignatureRequest, expectedResponse []byte) { + return message.SignatureRequest{ + MessageID: messageID, + }, signature + }, + verifyStats: func(t *testing.T, stats *stats.MockHandlerStats) { + assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestCount) + assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestHit) + assert.Greater(t, mockHandlerStats.SignatureRequestDuration, time.Duration(0)) + }, + }, + "unknown": { + setup: func() (request message.SignatureRequest, expectedResponse []byte) { + return message.SignatureRequest{ + MessageID: unknownMessageID, + }, nil + }, + verifyStats: func(t *testing.T, stats *stats.MockHandlerStats) { + assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestCount) + assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestMiss) + assert.Greater(t, mockHandlerStats.SignatureRequestDuration, time.Duration(0)) + }, + }, + } + + for name, test := range tests { + // Reset stats before each test + mockHandlerStats.Reset() + + t.Run(name, func(t *testing.T) { + request, expectedResponse := test.setup() + responseBytes, err := signatureRequestHandler.OnSignatureRequest(context.Background(), ids.GenerateTestNodeID(), 1, request) + assert.NoError(t, err) + + // If the expected response is empty, assert that the handler returns an empty response and return early. + if len(expectedResponse) == 0 { + assert.Len(t, responseBytes, 0, "expected response to be empty") + return + } + var response message.SignatureResponse + if _, err = message.Codec.Unmarshal(responseBytes, &response); err != nil { + t.Fatal("error unmarshalling SignatureResponse", err) + } + + assert.Equal(t, expectedResponse, response.Signature[:]) + test.verifyStats(t, mockHandlerStats) + }) + } +} diff --git a/sync/handlers/stats/mock_stats.go b/sync/handlers/stats/mock_stats.go index 59d2433172..407b1c4b7b 100644 --- a/sync/handlers/stats/mock_stats.go +++ b/sync/handlers/stats/mock_stats.go @@ -42,6 +42,11 @@ type MockHandlerStats struct { SnapshotReadTime, GenerateRangeProofTime, LeafRequestProcessingTimeSum time.Duration + + SignatureRequestCount, + SignatureRequestHit, + SignatureRequestMiss uint32 + SignatureRequestDuration time.Duration } func (m *MockHandlerStats) Reset() { @@ -73,6 +78,10 @@ func (m *MockHandlerStats) Reset() { m.SnapshotReadTime = 0 m.GenerateRangeProofTime = 0 m.LeafRequestProcessingTimeSum = 0 + m.SignatureRequestCount = 0 + m.SignatureRequestHit = 0 + m.SignatureRequestMiss = 0 + m.SignatureRequestDuration = 0 } func (m *MockHandlerStats) IncBlockRequest() { @@ -230,3 +239,27 @@ func (m *MockHandlerStats) IncSnapshotSegmentInvalid() { defer m.lock.Unlock() m.SnapshotSegmentInvalidCount++ } + +func (m *MockHandlerStats) IncSignatureRequest() { + m.lock.Lock() + defer m.lock.Unlock() + m.SignatureRequestCount++ +} + +func (m *MockHandlerStats) IncSignatureHit() { + m.lock.Lock() + defer m.lock.Unlock() + m.SignatureRequestHit++ +} + +func (m *MockHandlerStats) IncSignatureMiss() { + m.lock.Lock() + defer m.lock.Unlock() + m.SignatureRequestMiss++ +} + +func (m *MockHandlerStats) UpdateSignatureRequestTime(duration time.Duration) { + m.lock.Lock() + defer m.lock.Unlock() + m.SignatureRequestDuration += duration +} diff --git a/sync/handlers/stats/stats.go b/sync/handlers/stats/stats.go index 6d19b62a86..1d61de0034 100644 --- a/sync/handlers/stats/stats.go +++ b/sync/handlers/stats/stats.go @@ -14,6 +14,7 @@ type HandlerStats interface { BlockRequestHandlerStats CodeRequestHandlerStats LeafsRequestHandlerStats + SignatureRequestHandlerStats } type BlockRequestHandlerStats interface { @@ -51,6 +52,13 @@ type LeafsRequestHandlerStats interface { IncSnapshotSegmentInvalid() } +type SignatureRequestHandlerStats interface { + IncSignatureRequest() + IncSignatureHit() + IncSignatureMiss() + UpdateSignatureRequestTime(duration time.Duration) +} + type handlerStats struct { // BlockRequestHandler metrics blockRequest metrics.Counter @@ -83,6 +91,12 @@ type handlerStats struct { snapshotReadSuccess metrics.Counter snapshotSegmentValid metrics.Counter snapshotSegmentInvalid metrics.Counter + + // SignatureRequestHandler metrics + signatureRequest metrics.Counter + signatureHit metrics.Counter + signatureMiss metrics.Counter + signatureProcessingTime metrics.Timer } func (h *handlerStats) IncBlockRequest() { @@ -166,6 +180,13 @@ func (h *handlerStats) IncSnapshotReadSuccess() { h.snapshotReadSuccess.Inc(1 func (h *handlerStats) IncSnapshotSegmentValid() { h.snapshotSegmentValid.Inc(1) } func (h *handlerStats) IncSnapshotSegmentInvalid() { h.snapshotSegmentInvalid.Inc(1) } +func (h *handlerStats) IncSignatureRequest() { h.signatureRequest.Inc(1) } +func (h *handlerStats) IncSignatureHit() { h.signatureHit.Inc(1) } +func (h *handlerStats) IncSignatureMiss() { h.signatureMiss.Inc(1) } +func (h *handlerStats) UpdateSignatureRequestTime(duration time.Duration) { + h.signatureProcessingTime.Update(duration) +} + func NewHandlerStats(enabled bool) HandlerStats { if !enabled { return NewNoopHandlerStats() @@ -202,6 +223,12 @@ func NewHandlerStats(enabled bool) HandlerStats { snapshotReadSuccess: metrics.GetOrRegisterCounter("leafs_request_snapshot_read_success", nil), snapshotSegmentValid: metrics.GetOrRegisterCounter("leafs_request_snapshot_segment_valid", nil), snapshotSegmentInvalid: metrics.GetOrRegisterCounter("leafs_request_snapshot_segment_invalid", nil), + + // initialize signature request stats + signatureRequest: metrics.GetOrRegisterCounter("signature_request_count", nil), + signatureHit: metrics.GetOrRegisterCounter("signature_request_hit", nil), + signatureMiss: metrics.GetOrRegisterCounter("signature_request_miss", nil), + signatureProcessingTime: metrics.GetOrRegisterTimer("signature_request_duration", nil), } } @@ -239,3 +266,7 @@ func (n *noopHandlerStats) IncSnapshotReadAttempt() func (n *noopHandlerStats) IncSnapshotReadSuccess() {} func (n *noopHandlerStats) IncSnapshotSegmentValid() {} func (n *noopHandlerStats) IncSnapshotSegmentInvalid() {} +func (n *noopHandlerStats) IncSignatureRequest() {} +func (n *noopHandlerStats) IncSignatureHit() {} +func (n *noopHandlerStats) IncSignatureMiss() {} +func (n *noopHandlerStats) UpdateSignatureRequestTime(duration time.Duration) {} From 6a44563d1a065203ea425063ef677f94b7e2673b Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Wed, 25 Jan 2023 14:49:27 -0800 Subject: [PATCH 25/50] use memdb and remove extra test --- plugin/evm/warp/backend_test.go | 41 ++++----------------------------- 1 file changed, 4 insertions(+), 37 deletions(-) diff --git a/plugin/evm/warp/backend_test.go b/plugin/evm/warp/backend_test.go index b29f47e6c1..642504ab27 100644 --- a/plugin/evm/warp/backend_test.go +++ b/plugin/evm/warp/backend_test.go @@ -9,8 +9,8 @@ import ( "reflect" "testing" - "github.com/ava-labs/avalanchego/cache" - "github.com/ava-labs/avalanchego/database/mockdb" + "github.com/ava-labs/avalanchego/database/memdb" + "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/utils/crypto/bls" @@ -39,12 +39,7 @@ func TestInterfaceStructOneToOne(t *testing.T) { } func TestWarpBackend_ValidMessage(t *testing.T) { - db := mockdb.New() - called := new(bool) - db.OnPut = func([]byte, []byte) error { - *called = true - return nil - } + db := memdb.New() snowCtx := snow.DefaultContextTest() snowCtx.TeleporterSigner = getTestSigner(t, sourceChainID) @@ -55,7 +50,6 @@ func TestWarpBackend_ValidMessage(t *testing.T) { require.NoError(t, err) err = be.AddMessage(context.Background(), unsignedMsg) require.NoError(t, err) - require.True(t, *called) // Verify that a signature is returned successfully, and compare to expected signature. messageID := hashing.ComputeHash256Array(unsignedMsg.Bytes()) @@ -68,12 +62,7 @@ func TestWarpBackend_ValidMessage(t *testing.T) { } func TestWarpBackend_InvalidMessage(t *testing.T) { - db := mockdb.New() - called := new(bool) - db.OnGet = func([]byte) ([]byte, error) { - *called = true - return nil, errTest - } + db := memdb.New() be := NewWarpBackend(snow.DefaultContextTest(), db, 500) unsignedMsg, err := teleporter.NewUnsignedMessage(sourceChainID, destinationChainID, payload) @@ -83,28 +72,6 @@ func TestWarpBackend_InvalidMessage(t *testing.T) { messageID := hashing.ComputeHash256Array(unsignedMsg.Bytes()) _, err = be.GetSignature(context.Background(), messageID) require.Error(t, err) - require.True(t, *called) -} - -func TestCacheTypes(t *testing.T) { - var ( - key = []byte("key") - val = []byte("value") - ) - - hash := hashing.ComputeHash256Array(key) - cache := &cache.LRU{Size: 100} - - // First put into cache with key type Hash256, resulting in cache miss. - cache.Put(hash, val) - _, ok := cache.Get(ids.ID(hash)) - require.False(t, ok) - - // Put into cache with key type ids.ID, cache hit. - cache.Put(ids.ID(hash), val) - res, ok := cache.Get(ids.ID(hash)) - require.True(t, ok) - require.Equal(t, val, res) } func getTestSigner(t *testing.T, sourceID ids.ID) teleporter.Signer { From fb76223a6292b82f78a7a3f78c53211e22cf70a0 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Thu, 26 Jan 2023 09:15:54 -0800 Subject: [PATCH 26/50] remove unused --- plugin/evm/warp/backend_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugin/evm/warp/backend_test.go b/plugin/evm/warp/backend_test.go index 642504ab27..9a4ba88655 100644 --- a/plugin/evm/warp/backend_test.go +++ b/plugin/evm/warp/backend_test.go @@ -5,7 +5,6 @@ package warp import ( "context" - "errors" "reflect" "testing" @@ -23,8 +22,6 @@ var ( sourceChainID = ids.GenerateTestID() destinationChainID = ids.GenerateTestID() payload = []byte("test") - - errTest = errors.New("non-nil error") ) func TestInterfaceStructOneToOne(t *testing.T) { From b7bfa178774efba86551c4b7bbccd356c1fab07f Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Thu, 26 Jan 2023 09:22:20 -0800 Subject: [PATCH 27/50] fix imports --- plugin/evm/warp/backend_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin/evm/warp/backend_test.go b/plugin/evm/warp/backend_test.go index 9a4ba88655..55ad796add 100644 --- a/plugin/evm/warp/backend_test.go +++ b/plugin/evm/warp/backend_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/ava-labs/avalanchego/database/memdb" - "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/utils/crypto/bls" From 3d47a868f637500bd95b728295366653720e8225 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Thu, 26 Jan 2023 10:47:23 -0800 Subject: [PATCH 28/50] fix imports --- plugin/evm/message/signature_request_test.go | 1 - sync/handlers/signature_request.go | 9 +++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/plugin/evm/message/signature_request_test.go b/plugin/evm/message/signature_request_test.go index 647761138e..290ee02fd0 100644 --- a/plugin/evm/message/signature_request_test.go +++ b/plugin/evm/message/signature_request_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/stretchr/testify/require" ) diff --git a/sync/handlers/signature_request.go b/sync/handlers/signature_request.go index 3106cbd73c..f4dcdea6be 100644 --- a/sync/handlers/signature_request.go +++ b/sync/handlers/signature_request.go @@ -7,16 +7,13 @@ import ( "context" "time" - "github.com/ava-labs/subnet-evm/sync/handlers/stats" - - "github.com/ava-labs/avalanchego/utils/crypto/bls" - - "github.com/ethereum/go-ethereum/log" - "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/plugin/evm/warp" + "github.com/ava-labs/subnet-evm/sync/handlers/stats" + "github.com/ethereum/go-ethereum/log" ) // SignatureRequestHandler is a peer.RequestHandler for message.SignatureRequest From cffb9ccfe03c89d3be06127db69be41283593e25 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Thu, 26 Jan 2023 10:49:15 -0800 Subject: [PATCH 29/50] nit --- sync/handlers/signature_request.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync/handlers/signature_request.go b/sync/handlers/signature_request.go index f4dcdea6be..47a605f941 100644 --- a/sync/handlers/signature_request.go +++ b/sync/handlers/signature_request.go @@ -41,7 +41,7 @@ func (s *SignatureRequestHandler) OnSignatureRequest(ctx context.Context, nodeID startTime := time.Now() s.stats.IncSignatureRequest() - // always report signature request time + // Always report signature request time defer func() { s.stats.UpdateSignatureRequestTime(time.Since(startTime)) }() From 005d90baa7785c154733ad08f0263a7877a3848b Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Fri, 27 Jan 2023 13:05:06 -0800 Subject: [PATCH 30/50] update license year --- plugin/evm/message/signature_request.go | 2 +- plugin/evm/message/signature_request_test.go | 2 +- sync/handlers/signature_request.go | 2 +- sync/handlers/signature_request_test.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugin/evm/message/signature_request.go b/plugin/evm/message/signature_request.go index c51be2449f..3ed8b64829 100644 --- a/plugin/evm/message/signature_request.go +++ b/plugin/evm/message/signature_request.go @@ -1,4 +1,4 @@ -// (c) 2022, Ava Labs, Inc. All rights reserved. +// (c) 2023, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. package message diff --git a/plugin/evm/message/signature_request_test.go b/plugin/evm/message/signature_request_test.go index 290ee02fd0..ad46eac790 100644 --- a/plugin/evm/message/signature_request_test.go +++ b/plugin/evm/message/signature_request_test.go @@ -1,4 +1,4 @@ -// (c) 2022, Ava Labs, Inc. All rights reserved. +// (c) 2023, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. package message diff --git a/sync/handlers/signature_request.go b/sync/handlers/signature_request.go index 47a605f941..b69eb33804 100644 --- a/sync/handlers/signature_request.go +++ b/sync/handlers/signature_request.go @@ -1,4 +1,4 @@ -// (c) 2022, Ava Labs, Inc. All rights reserved. +// (c) 2023, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. package handlers diff --git a/sync/handlers/signature_request_test.go b/sync/handlers/signature_request_test.go index 61517844b7..c2fa24ee70 100644 --- a/sync/handlers/signature_request_test.go +++ b/sync/handlers/signature_request_test.go @@ -1,4 +1,4 @@ -// (c) 2021-2022, Ava Labs, Inc. All rights reserved. +// (c) 2023, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. package handlers From 66a82382672cd6c857f1045f54c0c1d9b97f7d69 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Fri, 27 Jan 2023 13:09:07 -0800 Subject: [PATCH 31/50] use require noError --- plugin/evm/message/signature_request_test.go | 4 +--- sync/handlers/signature_request_test.go | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/plugin/evm/message/signature_request_test.go b/plugin/evm/message/signature_request_test.go index ad46eac790..9e4c2fd96e 100644 --- a/plugin/evm/message/signature_request_test.go +++ b/plugin/evm/message/signature_request_test.go @@ -41,9 +41,7 @@ func TestMarshalSignatureRequest(t *testing.T) { func TestMarshalSignatureResponse(t *testing.T) { var signature [bls.SignatureLen]byte sig, err := hex.DecodeString("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef") - if err != nil { - t.Error("failed to decode string to hex") - } + require.NoError(t, err, "failed to decode string to hex") copy(signature[:], sig) signatureResponse := SignatureResponse{ diff --git a/sync/handlers/signature_request_test.go b/sync/handlers/signature_request_test.go index c2fa24ee70..bbaf77017b 100644 --- a/sync/handlers/signature_request_test.go +++ b/sync/handlers/signature_request_test.go @@ -87,9 +87,8 @@ func TestSignatureHandler(t *testing.T) { return } var response message.SignatureResponse - if _, err = message.Codec.Unmarshal(responseBytes, &response); err != nil { - t.Fatal("error unmarshalling SignatureResponse", err) - } + _, err = message.Codec.Unmarshal(responseBytes, &response) + require.NoError(t, err, "error unmarshalling SignatureResponse") assert.Equal(t, expectedResponse, response.Signature[:]) test.verifyStats(t, mockHandlerStats) From 9a99797a909497828229624f9bec409fc88c14ae Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Mon, 30 Jan 2023 11:58:49 -0800 Subject: [PATCH 32/50] saving message in db and pr fixes --- plugin/evm/warp/backend.go | 25 +++++++++++++------ plugin/evm/warp/backend_test.go | 44 ++++++++++++++++++++------------- 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/plugin/evm/warp/backend.go b/plugin/evm/warp/backend.go index e021ac0bbd..84b95eec77 100644 --- a/plugin/evm/warp/backend.go +++ b/plugin/evm/warp/backend.go @@ -46,17 +46,16 @@ func NewWarpBackend(snowCtx *snow.Context, db database.Database, signatureCacheS func (w *warpBackend) AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error { messageID := hashing.ComputeHash256Array(unsignedMessage.Bytes()) - // We generate the signature here and only save the signature in the db and cache. - // It is left to smart contracts built on top of Warp to save messages if required. + // We save the message instead of signature for db, in case for bls key changes. + if err := w.db.Put(messageID[:], unsignedMessage.Bytes()); err != nil { + return fmt.Errorf("failed to put warp signature in db: %w", err) + } + signature, err := w.snowCtx.TeleporterSigner.Sign(unsignedMessage) if err != nil { return fmt.Errorf("failed to sign warp message: %w", err) } - if err := w.db.Put(messageID[:], signature); err != nil { - return fmt.Errorf("failed to put warp signature in db: %w", err) - } - w.signatureCache.Put(ids.ID(messageID), signature) return nil } @@ -66,9 +65,19 @@ func (w *warpBackend) GetSignature(ctx context.Context, messageID ids.ID) ([]byt return sig.([]byte), nil } - signature, err := w.db.Get(messageID[:]) + unsignedMessageBytes, err := w.db.Get(messageID[:]) + if err != nil { + return nil, fmt.Errorf("failed to get warp message %s from db: %w", messageID.String(), err) + } + + unsignedMessage, err := teleporter.ParseUnsignedMessage(unsignedMessageBytes) + if err != nil { + return nil, fmt.Errorf("failed to parse unsigned message %s: %w", messageID.String(), err) + } + + signature, err := w.snowCtx.TeleporterSigner.Sign(unsignedMessage) if err != nil { - return nil, fmt.Errorf("failed to get warp signature for message %s from db: %w", messageID.String(), err) + return nil, fmt.Errorf("failed to sign warp message: %w", err) } w.signatureCache.Put(messageID[:], signature) diff --git a/plugin/evm/warp/backend_test.go b/plugin/evm/warp/backend_test.go index 55ad796add..c36ac9e30f 100644 --- a/plugin/evm/warp/backend_test.go +++ b/plugin/evm/warp/backend_test.go @@ -5,7 +5,6 @@ package warp import ( "context" - "reflect" "testing" "github.com/ava-labs/avalanchego/database/memdb" @@ -23,22 +22,13 @@ var ( payload = []byte("test") ) -func TestInterfaceStructOneToOne(t *testing.T) { - // checks struct provides at least the methods signatures in the interface - var _ WarpBackend = (*warpBackend)(nil) - // checks interface and struct have the same number of methods - backendType := reflect.TypeOf(&warpBackend{}) - BackendType := reflect.TypeOf((*WarpBackend)(nil)).Elem() - if backendType.NumMethod() != BackendType.NumMethod() { - t.Fatalf("no 1 to 1 compliance between struct methods (%v) and interface methods (%v)", backendType.NumMethod(), BackendType.NumMethod()) - } -} - -func TestWarpBackend_ValidMessage(t *testing.T) { +func TestAddAndGetValidMessage(t *testing.T) { db := memdb.New() snowCtx := snow.DefaultContextTest() - snowCtx.TeleporterSigner = getTestSigner(t, sourceChainID) + sk, err := bls.NewSecretKey() + require.NoError(t, err) + snowCtx.TeleporterSigner = teleporter.NewSigner(sk, sourceChainID) be := NewWarpBackend(snowCtx, db, 500) // Create a new unsigned message and add it to the warp backend. @@ -57,7 +47,7 @@ func TestWarpBackend_ValidMessage(t *testing.T) { require.Equal(t, expectedSig, signature) } -func TestWarpBackend_InvalidMessage(t *testing.T) { +func TestAddAndGetUnknownMessage(t *testing.T) { db := memdb.New() be := NewWarpBackend(snow.DefaultContextTest(), db, 500) @@ -70,9 +60,29 @@ func TestWarpBackend_InvalidMessage(t *testing.T) { require.Error(t, err) } -func getTestSigner(t *testing.T, sourceID ids.ID) teleporter.Signer { +func TestZeroSizedCache(t *testing.T) { + db := memdb.New() + + snowCtx := snow.DefaultContextTest() sk, err := bls.NewSecretKey() require.NoError(t, err) + snowCtx.TeleporterSigner = teleporter.NewSigner(sk, sourceChainID) + + // Verify zero sized cache works normally, because the lru cache will be initialized to size 1 for any size parameter <= 0. + be := NewWarpBackend(snowCtx, db, 0) + + // Create a new unsigned message and add it to the warp backend. + unsignedMsg, err := teleporter.NewUnsignedMessage(sourceChainID, destinationChainID, payload) + require.NoError(t, err) + err = be.AddMessage(context.Background(), unsignedMsg) + require.NoError(t, err) - return teleporter.NewSigner(sk, sourceID) + // Verify that a signature is returned successfully, and compare to expected signature. + messageID := hashing.ComputeHash256Array(unsignedMsg.Bytes()) + signature, err := be.GetSignature(context.Background(), messageID) + require.NoError(t, err) + + expectedSig, err := snowCtx.TeleporterSigner.Sign(unsignedMsg) + require.NoError(t, err) + require.Equal(t, expectedSig, signature) } From 70e1d00d22e30dc5327327ff9509618078af4edf Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Mon, 30 Jan 2023 16:46:08 -0800 Subject: [PATCH 33/50] create noop signature handler and refactor code handler --- .../signature_request.go | 19 +++++++++++++++---- .../signature_request_test.go | 0 sync/handlers/handler.go | 8 +++++--- 3 files changed, 20 insertions(+), 7 deletions(-) rename {sync/handlers => handlers}/signature_request.go (73%) rename {sync/handlers => handlers}/signature_request_test.go (100%) diff --git a/sync/handlers/signature_request.go b/handlers/signature_request.go similarity index 73% rename from sync/handlers/signature_request.go rename to handlers/signature_request.go index b69eb33804..58e6797226 100644 --- a/sync/handlers/signature_request.go +++ b/handlers/signature_request.go @@ -18,14 +18,19 @@ import ( // SignatureRequestHandler is a peer.RequestHandler for message.SignatureRequest // serving requested BLS signature data -type SignatureRequestHandler struct { +type SignatureRequestHandler interface { + OnSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) +} + +// signatureRequestHandler implements the SignatureRequestHandler interface +type signatureRequestHandler struct { backend warp.WarpBackend codec codec.Manager stats stats.SignatureRequestHandlerStats } -func NewSignatureRequestHandler(backend warp.WarpBackend, codec codec.Manager, stats stats.SignatureRequestHandlerStats) *SignatureRequestHandler { - return &SignatureRequestHandler{ +func NewSignatureRequestHandler(backend warp.WarpBackend, codec codec.Manager, stats stats.SignatureRequestHandlerStats) SignatureRequestHandler { + return &signatureRequestHandler{ backend: backend, codec: codec, stats: stats, @@ -37,7 +42,7 @@ func NewSignatureRequestHandler(backend warp.WarpBackend, codec codec.Manager, s // Expects returned errors to be treated as FATAL // Returns empty response if signature is not found // Assumes ctx is active -func (s *SignatureRequestHandler) OnSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) { +func (s *signatureRequestHandler) OnSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) { startTime := time.Now() s.stats.IncSignatureRequest() @@ -65,3 +70,9 @@ func (s *SignatureRequestHandler) OnSignatureRequest(ctx context.Context, nodeID return responseBytes, nil } + +type NoopSignatureRequestHandler struct{} + +func (s *NoopSignatureRequestHandler) OnSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) { + return nil, nil +} diff --git a/sync/handlers/signature_request_test.go b/handlers/signature_request_test.go similarity index 100% rename from sync/handlers/signature_request_test.go rename to handlers/signature_request_test.go diff --git a/sync/handlers/handler.go b/sync/handlers/handler.go index b84a8d0686..1432ff780f 100644 --- a/sync/handlers/handler.go +++ b/sync/handlers/handler.go @@ -6,6 +6,8 @@ package handlers import ( "context" + "github.com/ava-labs/subnet-evm/handlers" + "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/subnet-evm/core/state/snapshot" @@ -35,7 +37,7 @@ type syncHandler struct { stateTrieLeafsRequestHandler *LeafsRequestHandler blockRequestHandler *BlockRequestHandler codeRequestHandler *CodeRequestHandler - signatureRequestHandler *SignatureRequestHandler + signatureRequestHandler handlers.SignatureRequestHandler } // NewSyncHandler constructs the handler for serving state sync. @@ -50,8 +52,8 @@ func NewSyncHandler( blockRequestHandler: NewBlockRequestHandler(provider, networkCodec, stats), codeRequestHandler: NewCodeRequestHandler(evmTrieDB.DiskDB(), networkCodec, stats), - // TODO: need to pass in the warp backend from the subnet-evm. - signatureRequestHandler: NewSignatureRequestHandler(nil, networkCodec, stats), + // TODO: need to pass in the warp backend from the subnet-evm to create signature request handler. + signatureRequestHandler: &handlers.NoopSignatureRequestHandler{}, } } From de89d5bd0247d7d0fd5fabf2039f97c2d13771b5 Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Wed, 1 Feb 2023 17:11:13 +0000 Subject: [PATCH 34/50] get signature endpoint --- plugin/evm/client.go | 9 +++++++++ plugin/evm/service.go | 16 ++++++++++++++++ plugin/evm/vm.go | 4 ++++ 3 files changed, 29 insertions(+) diff --git a/plugin/evm/client.go b/plugin/evm/client.go index 78e55d73f4..b1f6cee69f 100644 --- a/plugin/evm/client.go +++ b/plugin/evm/client.go @@ -8,7 +8,9 @@ import ( "fmt" "github.com/ava-labs/avalanchego/api" + "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/rpc" + "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ethereum/go-ethereum/log" ) @@ -23,6 +25,7 @@ type Client interface { LockProfile(ctx context.Context) error SetLogLevel(ctx context.Context, level log.Lvl) error GetVMConfig(ctx context.Context) (*Config, error) + GetSignature(ctx context.Context, signatureRequest message.SignatureRequest) (*[bls.SignatureLen]byte, error) } // Client implementation for interacting with EVM [chain] @@ -72,3 +75,9 @@ func (c *client) GetVMConfig(ctx context.Context) (*Config, error) { err := c.requester.SendRequest(ctx, "admin.getVMConfig", struct{}{}, res) return res.Config, err } + +func (c *client) GetSignature(ctx context.Context, signatureRequest message.SignatureRequest) (*[bls.SignatureLen]byte, error) { + res := &message.SignatureResponse{} + err := c.requester.SendRequest(ctx, "snowman.getSignature", &signatureRequest, res) + return &res.Signature, err +} diff --git a/plugin/evm/service.go b/plugin/evm/service.go index 54b5021a45..64b241b75c 100644 --- a/plugin/evm/service.go +++ b/plugin/evm/service.go @@ -7,6 +7,8 @@ import ( "context" "math/big" + "github.com/ava-labs/avalanchego/utils/crypto/bls" + "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" ) @@ -43,3 +45,17 @@ func (api *SnowmanAPI) IssueBlock(ctx context.Context) error { api.vm.builder.signalTxsReady() return nil } + +func (api *SnowmanAPI) GetSignature(ctx context.Context, signatureRequest *message.SignatureRequest) (*message.SignatureResponse, error) { + sig, err := api.vm.backend.GetSignature(ctx, signatureRequest.MessageID) + if err != nil { + log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) + return nil, nil + } + var signature [bls.SignatureLen]byte + copy(signature[:], sig) + response := message.SignatureResponse{ + Signature: signature, + } + return &response, nil +} diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index cc08501e2b..f87486e575 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -32,6 +32,7 @@ import ( "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/peer" "github.com/ava-labs/subnet-evm/plugin/evm/message" + "github.com/ava-labs/subnet-evm/plugin/evm/warp" "github.com/ava-labs/subnet-evm/rpc" statesyncclient "github.com/ava-labs/subnet-evm/sync/client" "github.com/ava-labs/subnet-evm/sync/client/stats" @@ -208,6 +209,9 @@ type VM struct { // State sync server and client StateSyncServer StateSyncClient + + // AWM backend + backend warp.WarpBackend } /* From 562c8f0d1058656c5da187c3c1806de968d92c5f Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Wed, 1 Feb 2023 19:03:38 +0000 Subject: [PATCH 35/50] add api arg to evm client --- plugin/evm/client.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin/evm/client.go b/plugin/evm/client.go index b1f6cee69f..72f3e080c9 100644 --- a/plugin/evm/client.go +++ b/plugin/evm/client.go @@ -34,16 +34,16 @@ type client struct { } // NewClient returns a Client for interacting with EVM [chain] -func NewClient(uri, chain string) Client { +func NewClient(uri, chain, api string) Client { return &client{ - requester: rpc.NewEndpointRequester(fmt.Sprintf("%s/ext/bc/%s/admin", uri, chain)), + requester: rpc.NewEndpointRequester(fmt.Sprintf("%s/ext/bc/%s/%s", uri, chain, api)), } } // NewCChainClient returns a Client for interacting with the C Chain func NewCChainClient(uri string) Client { // TODO: Update for Subnet-EVM compatibility - return NewClient(uri, "C") + return NewClient(uri, "C", "admin") } func (c *client) StartCPUProfiler(ctx context.Context) error { From 76febbaab07ab5d246bc7034604603449962e005 Mon Sep 17 00:00:00 2001 From: minghinmatthewlam Date: Thu, 2 Feb 2023 12:41:09 -0800 Subject: [PATCH 36/50] Update sync/handlers/handler.go Co-authored-by: aaronbuchwald --- sync/handlers/handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync/handlers/handler.go b/sync/handlers/handler.go index 1432ff780f..2515428587 100644 --- a/sync/handlers/handler.go +++ b/sync/handlers/handler.go @@ -52,7 +52,7 @@ func NewSyncHandler( blockRequestHandler: NewBlockRequestHandler(provider, networkCodec, stats), codeRequestHandler: NewCodeRequestHandler(evmTrieDB.DiskDB(), networkCodec, stats), - // TODO: need to pass in the warp backend from the subnet-evm to create signature request handler. + // TODO: initialize actual signature request handler when warp is ready signatureRequestHandler: &handlers.NoopSignatureRequestHandler{}, } } From ce25575d7af572363116622a1a996991ab6c01b1 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Thu, 2 Feb 2023 13:19:27 -0800 Subject: [PATCH 37/50] update backend return value --- handlers/signature_request.go | 5 +---- handlers/signature_request_test.go | 6 ++++-- plugin/evm/warp/backend.go | 28 +++++++++++++++++++--------- plugin/evm/warp/backend_test.go | 8 ++++++-- 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/handlers/signature_request.go b/handlers/signature_request.go index 58e6797226..071b51c426 100644 --- a/handlers/signature_request.go +++ b/handlers/signature_request.go @@ -9,7 +9,6 @@ import ( "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/plugin/evm/warp" "github.com/ava-labs/subnet-evm/sync/handlers/stats" @@ -51,8 +50,7 @@ func (s *signatureRequestHandler) OnSignatureRequest(ctx context.Context, nodeID s.stats.UpdateSignatureRequestTime(time.Since(startTime)) }() - var signature [bls.SignatureLen]byte - sig, err := s.backend.GetSignature(ctx, signatureRequest.MessageID) + signature, err := s.backend.GetSignature(ctx, signatureRequest.MessageID) if err != nil { log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) s.stats.IncSignatureMiss() @@ -60,7 +58,6 @@ func (s *signatureRequestHandler) OnSignatureRequest(ctx context.Context, nodeID } s.stats.IncSignatureHit() - copy(signature[:], sig) response := message.SignatureResponse{Signature: signature} responseBytes, err := s.codec.Marshal(message.Version, response) if err != nil { diff --git a/handlers/signature_request_test.go b/handlers/signature_request_test.go index bbaf77017b..fe29a1654c 100644 --- a/handlers/signature_request_test.go +++ b/handlers/signature_request_test.go @@ -50,7 +50,7 @@ func TestSignatureHandler(t *testing.T) { setup: func() (request message.SignatureRequest, expectedResponse []byte) { return message.SignatureRequest{ MessageID: messageID, - }, signature + }, signature[:] }, verifyStats: func(t *testing.T, stats *stats.MockHandlerStats) { assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestCount) @@ -90,7 +90,9 @@ func TestSignatureHandler(t *testing.T) { _, err = message.Codec.Unmarshal(responseBytes, &response) require.NoError(t, err, "error unmarshalling SignatureResponse") - assert.Equal(t, expectedResponse, response.Signature[:]) + var expectedSignature [bls.SignatureLen]byte + copy(expectedSignature[:], expectedResponse) + assert.Equal(t, expectedSignature, response.Signature) test.verifyStats(t, mockHandlerStats) }) } diff --git a/plugin/evm/warp/backend.go b/plugin/evm/warp/backend.go index ac865daf51..927dae7ea2 100644 --- a/plugin/evm/warp/backend.go +++ b/plugin/evm/warp/backend.go @@ -7,6 +7,8 @@ import ( "context" "fmt" + "github.com/ava-labs/avalanchego/utils/crypto/bls" + "github.com/ava-labs/avalanchego/cache" "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/ids" @@ -15,7 +17,11 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/teleporter" ) -var _ WarpBackend = &warpBackend{} +var ( + _ WarpBackend = &warpBackend{} + + emptySignature = [bls.SignatureLen]byte{} +) // WarpBackend 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. @@ -24,7 +30,7 @@ type WarpBackend interface { AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error // GetSignature returns the signature of the requested message hash. - GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) + GetSignature(ctx context.Context, messageHash ids.ID) ([bls.SignatureLen]byte, error) } // warpBackend implements WarpBackend, keeps track of warp messages, and generates message signatures. @@ -53,35 +59,39 @@ func (w *warpBackend) AddMessage(ctx context.Context, unsignedMessage *teleporte return fmt.Errorf("failed to put warp signature in db: %w", err) } - signature, err := w.snowCtx.TeleporterSigner.Sign(unsignedMessage) + var signature [bls.SignatureLen]byte + sig, err := w.snowCtx.TeleporterSigner.Sign(unsignedMessage) if err != nil { return fmt.Errorf("failed to sign warp message: %w", err) } + copy(signature[:], sig) w.signatureCache.Put(ids.ID(messageID), signature) return nil } -func (w *warpBackend) GetSignature(ctx context.Context, messageID ids.ID) ([]byte, error) { +func (w *warpBackend) GetSignature(ctx context.Context, messageID ids.ID) ([bls.SignatureLen]byte, error) { if sig, ok := w.signatureCache.Get(messageID); ok { - return sig.([]byte), nil + return sig.([bls.SignatureLen]byte), nil } unsignedMessageBytes, err := w.db.Get(messageID[:]) if err != nil { - return nil, fmt.Errorf("failed to get warp message %s from db: %w", messageID.String(), err) + return emptySignature, fmt.Errorf("failed to get warp message %s from db: %w", messageID.String(), err) } unsignedMessage, err := teleporter.ParseUnsignedMessage(unsignedMessageBytes) if err != nil { - return nil, fmt.Errorf("failed to parse unsigned message %s: %w", messageID.String(), err) + return emptySignature, fmt.Errorf("failed to parse unsigned message %s: %w", messageID.String(), err) } - signature, err := w.snowCtx.TeleporterSigner.Sign(unsignedMessage) + var signature [bls.SignatureLen]byte + sig, err := w.snowCtx.TeleporterSigner.Sign(unsignedMessage) if err != nil { - return nil, fmt.Errorf("failed to sign warp message: %w", err) + return emptySignature, fmt.Errorf("failed to sign warp message: %w", err) } + copy(signature[:], sig) w.signatureCache.Put(messageID[:], signature) return signature, nil } diff --git a/plugin/evm/warp/backend_test.go b/plugin/evm/warp/backend_test.go index de38246d30..557af26a60 100644 --- a/plugin/evm/warp/backend_test.go +++ b/plugin/evm/warp/backend_test.go @@ -42,9 +42,11 @@ func TestAddAndGetValidMessage(t *testing.T) { signature, err := backend.GetSignature(context.Background(), messageID) require.NoError(t, err) + var expectedSignature [bls.SignatureLen]byte expectedSig, err := snowCtx.TeleporterSigner.Sign(unsignedMsg) require.NoError(t, err) - require.Equal(t, expectedSig, signature) + copy(expectedSignature[:], expectedSig) + require.Equal(t, expectedSignature, signature) } func TestAddAndGetUnknownMessage(t *testing.T) { @@ -82,7 +84,9 @@ func TestZeroSizedCache(t *testing.T) { signature, err := backend.GetSignature(context.Background(), messageID) require.NoError(t, err) + var expectedSignature [bls.SignatureLen]byte expectedSig, err := snowCtx.TeleporterSigner.Sign(unsignedMsg) require.NoError(t, err) - require.Equal(t, expectedSig, signature) + copy(expectedSignature[:], expectedSig) + require.Equal(t, expectedSignature, signature) } From 9d93fd1d62f65298ba33caae38d074426ba04d7f Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Thu, 2 Feb 2023 15:47:48 -0800 Subject: [PATCH 38/50] refactor handlers to network handler --- handlers/handler.go | 60 ++++++ handlers/signature_request.go | 2 +- handlers/signature_request_test.go | 2 +- handlers/stats/mock_stats.go | 164 +++++++++++++++++ handlers/stats/stats.go | 285 +++++++++++++++++++++++++++++ plugin/evm/message/handler.go | 2 +- plugin/evm/vm.go | 13 +- sync/handlers/handler.go | 51 ------ sync/handlers/stats/mock_stats.go | 33 ---- sync/handlers/stats/stats.go | 31 ---- 10 files changed, 516 insertions(+), 127 deletions(-) create mode 100644 handlers/handler.go create mode 100644 handlers/stats/mock_stats.go create mode 100644 handlers/stats/stats.go diff --git a/handlers/handler.go b/handlers/handler.go new file mode 100644 index 0000000000..c1afb37438 --- /dev/null +++ b/handlers/handler.go @@ -0,0 +1,60 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package handlers + +import ( + "context" + + "github.com/ava-labs/avalanchego/codec" + "github.com/ava-labs/subnet-evm/handlers/stats" + "github.com/ava-labs/subnet-evm/metrics" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/subnet-evm/plugin/evm/message" + "github.com/ava-labs/subnet-evm/sync/handlers" + syncStats "github.com/ava-labs/subnet-evm/sync/handlers/stats" + "github.com/ava-labs/subnet-evm/trie" +) + +var _ message.RequestHandler = &networkHandler{} + +type networkHandler struct { + stateTrieLeafsRequestHandler *handlers.LeafsRequestHandler + blockRequestHandler *handlers.BlockRequestHandler + codeRequestHandler *handlers.CodeRequestHandler + signatureRequestHandler SignatureRequestHandler +} + +func NewNetworkHandler( + provider handlers.SyncDataProvider, + evmTrieDB *trie.Database, + networkCodec codec.Manager, +) message.RequestHandler { + syncStats := syncStats.NewHandlerStats(metrics.Enabled) + handlerStats := stats.NewHandlerStats(metrics.Enabled, syncStats) + return &networkHandler{ + stateTrieLeafsRequestHandler: handlers.NewLeafsRequestHandler(evmTrieDB, provider, networkCodec, handlerStats), + blockRequestHandler: handlers.NewBlockRequestHandler(provider, networkCodec, handlerStats), + codeRequestHandler: handlers.NewCodeRequestHandler(evmTrieDB.DiskDB(), networkCodec, handlerStats), + + // TODO: initialize actual signature request handler when warp is ready + signatureRequestHandler: &NoopSignatureRequestHandler{}, + } +} + +func (n networkHandler) HandleTrieLeafsRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, leafsRequest message.LeafsRequest) ([]byte, error) { + return n.stateTrieLeafsRequestHandler.OnLeafsRequest(ctx, nodeID, requestID, leafsRequest) +} + +func (n networkHandler) HandleBlockRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, blockRequest message.BlockRequest) ([]byte, error) { + return n.blockRequestHandler.OnBlockRequest(ctx, nodeID, requestID, blockRequest) +} + +func (n networkHandler) HandleCodeRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, codeRequest message.CodeRequest) ([]byte, error) { + return n.codeRequestHandler.OnCodeRequest(ctx, nodeID, requestID, codeRequest) +} + +func (n networkHandler) HandleSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) { + return n.signatureRequestHandler.OnSignatureRequest(ctx, nodeID, requestID, signatureRequest) +} diff --git a/handlers/signature_request.go b/handlers/signature_request.go index 071b51c426..c451d1d154 100644 --- a/handlers/signature_request.go +++ b/handlers/signature_request.go @@ -9,9 +9,9 @@ import ( "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/subnet-evm/handlers/stats" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/plugin/evm/warp" - "github.com/ava-labs/subnet-evm/sync/handlers/stats" "github.com/ethereum/go-ethereum/log" ) diff --git a/handlers/signature_request_test.go b/handlers/signature_request_test.go index fe29a1654c..0a2d5c75ca 100644 --- a/handlers/signature_request_test.go +++ b/handlers/signature_request_test.go @@ -14,9 +14,9 @@ import ( "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/vms/platformvm/teleporter" + "github.com/ava-labs/subnet-evm/handlers/stats" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/plugin/evm/warp" - "github.com/ava-labs/subnet-evm/sync/handlers/stats" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/handlers/stats/mock_stats.go b/handlers/stats/mock_stats.go new file mode 100644 index 0000000000..ab9b4e340d --- /dev/null +++ b/handlers/stats/mock_stats.go @@ -0,0 +1,164 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package stats + +import ( + "sync" + "time" + + syncStats "github.com/ava-labs/subnet-evm/sync/handlers/stats" +) + +var _ HandlerStats = &MockHandlerStats{} + +// MockHandlerStats is mock for capturing and asserting on handler metrics in test +type MockHandlerStats struct { + lock sync.Mutex + + syncHandlerStats syncStats.MockHandlerStats + + SignatureRequestCount, + SignatureRequestHit, + SignatureRequestMiss uint32 + SignatureRequestDuration time.Duration +} + +func (m *MockHandlerStats) Reset() { + m.lock.Lock() + defer m.lock.Unlock() + m.syncHandlerStats.Reset() + + m.SignatureRequestCount = 0 + m.SignatureRequestHit = 0 + m.SignatureRequestMiss = 0 + m.SignatureRequestDuration = 0 +} + +func (m *MockHandlerStats) IncBlockRequest() { + m.syncHandlerStats.IncBlockRequest() +} + +func (m *MockHandlerStats) IncMissingBlockHash() { + m.syncHandlerStats.IncMissingBlockHash() +} + +func (m *MockHandlerStats) UpdateBlocksReturned(num uint16) { + m.syncHandlerStats.UpdateBlocksReturned(num) +} + +func (m *MockHandlerStats) UpdateBlockRequestProcessingTime(duration time.Duration) { + m.syncHandlerStats.UpdateBlockRequestProcessingTime(duration) +} + +func (m *MockHandlerStats) IncCodeRequest() { + m.syncHandlerStats.IncCodeRequest() +} + +func (m *MockHandlerStats) IncMissingCodeHash() { + m.syncHandlerStats.IncMissingCodeHash() +} + +func (m *MockHandlerStats) IncTooManyHashesRequested() { + m.syncHandlerStats.IncTooManyHashesRequested() +} + +func (m *MockHandlerStats) IncDuplicateHashesRequested() { + m.syncHandlerStats.IncDuplicateHashesRequested() +} + +func (m *MockHandlerStats) UpdateCodeReadTime(duration time.Duration) { + m.syncHandlerStats.UpdateCodeReadTime(duration) +} + +func (m *MockHandlerStats) UpdateCodeBytesReturned(bytes uint32) { + m.syncHandlerStats.UpdateCodeBytesReturned(bytes) +} + +func (m *MockHandlerStats) IncLeafsRequest() { + m.syncHandlerStats.IncLeafsRequest() +} + +func (m *MockHandlerStats) IncInvalidLeafsRequest() { + m.syncHandlerStats.IncInvalidLeafsRequest() +} + +func (m *MockHandlerStats) UpdateLeafsReturned(numLeafs uint16) { + m.syncHandlerStats.UpdateLeafsReturned(numLeafs) +} + +func (m *MockHandlerStats) UpdateLeafsRequestProcessingTime(duration time.Duration) { + m.syncHandlerStats.UpdateLeafsRequestProcessingTime(duration) +} + +func (m *MockHandlerStats) UpdateReadLeafsTime(duration time.Duration) { + m.syncHandlerStats.UpdateReadLeafsTime(duration) +} + +func (m *MockHandlerStats) UpdateSnapshotReadTime(duration time.Duration) { + m.syncHandlerStats.UpdateSnapshotReadTime(duration) +} + +func (m *MockHandlerStats) UpdateGenerateRangeProofTime(duration time.Duration) { + m.syncHandlerStats.UpdateGenerateRangeProofTime(duration) +} + +func (m *MockHandlerStats) UpdateRangeProofValsReturned(numProofVals int64) { + m.syncHandlerStats.UpdateRangeProofValsReturned(numProofVals) +} + +func (m *MockHandlerStats) IncMissingRoot() { + m.syncHandlerStats.IncMissingRoot() +} + +func (m *MockHandlerStats) IncTrieError() { + m.syncHandlerStats.IncTrieError() +} + +func (m *MockHandlerStats) IncProofError() { + m.syncHandlerStats.IncProofError() +} + +func (m *MockHandlerStats) IncSnapshotReadError() { + m.syncHandlerStats.IncSnapshotReadError() +} + +func (m *MockHandlerStats) IncSnapshotReadAttempt() { + m.syncHandlerStats.IncSnapshotReadAttempt() +} + +func (m *MockHandlerStats) IncSnapshotReadSuccess() { + m.syncHandlerStats.IncSnapshotReadSuccess() +} + +func (m *MockHandlerStats) IncSnapshotSegmentValid() { + m.syncHandlerStats.IncSnapshotSegmentValid() +} + +func (m *MockHandlerStats) IncSnapshotSegmentInvalid() { + m.syncHandlerStats.IncSnapshotSegmentInvalid() +} + +func (m *MockHandlerStats) IncSignatureRequest() { + m.lock.Lock() + defer m.lock.Unlock() + m.SignatureRequestCount++ +} + +func (m *MockHandlerStats) IncSignatureHit() { + m.lock.Lock() + defer m.lock.Unlock() + m.SignatureRequestHit++ +} + +func (m *MockHandlerStats) IncSignatureMiss() { + m.lock.Lock() + defer m.lock.Unlock() + m.SignatureRequestMiss++ +} + +func (m *MockHandlerStats) UpdateSignatureRequestTime(duration time.Duration) { + m.lock.Lock() + defer m.lock.Unlock() + m.SignatureRequestDuration += duration +} diff --git a/handlers/stats/stats.go b/handlers/stats/stats.go new file mode 100644 index 0000000000..3de14b06c3 --- /dev/null +++ b/handlers/stats/stats.go @@ -0,0 +1,285 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package stats + +import ( + "time" + + "github.com/ava-labs/subnet-evm/metrics" + syncStats "github.com/ava-labs/subnet-evm/sync/handlers/stats" +) + +var ( + _ HandlerStats = &handlerStats{} + _ HandlerStats = &noopHandlerStats{} +) + +// HandlerStats reports prometheus metrics for the network handlers +type HandlerStats interface { + SignatureRequestHandlerStats + syncStats.HandlerStats +} + +type SignatureRequestHandlerStats interface { + IncSignatureRequest() + IncSignatureHit() + IncSignatureMiss() + UpdateSignatureRequestTime(duration time.Duration) +} + +type handlerStats struct { + syncHandlerStats syncStats.HandlerStats + + // SignatureRequestHandler metrics + signatureRequest metrics.Counter + signatureHit metrics.Counter + signatureMiss metrics.Counter + signatureProcessingTime metrics.Timer +} + +func (h *handlerStats) IncBlockRequest() { + h.syncHandlerStats.IncBlockRequest() +} + +func (h *handlerStats) IncMissingBlockHash() { + h.syncHandlerStats.IncMissingBlockHash() +} + +func (h *handlerStats) UpdateBlocksReturned(num uint16) { + h.syncHandlerStats.UpdateBlocksReturned(num) +} + +func (h *handlerStats) UpdateBlockRequestProcessingTime(duration time.Duration) { + h.syncHandlerStats.UpdateBlockRequestProcessingTime(duration) +} + +func (h *handlerStats) IncCodeRequest() { + h.syncHandlerStats.IncCodeRequest() +} + +func (h *handlerStats) IncMissingCodeHash() { + h.syncHandlerStats.IncMissingCodeHash() +} + +func (h *handlerStats) IncTooManyHashesRequested() { + h.syncHandlerStats.IncTooManyHashesRequested() +} + +func (h *handlerStats) IncDuplicateHashesRequested() { + h.syncHandlerStats.IncDuplicateHashesRequested() +} + +func (h *handlerStats) UpdateCodeReadTime(duration time.Duration) { + h.syncHandlerStats.UpdateCodeReadTime(duration) +} + +func (h *handlerStats) UpdateCodeBytesReturned(bytes uint32) { + h.syncHandlerStats.UpdateCodeBytesReturned(bytes) +} + +func (h *handlerStats) IncLeafsRequest() { + h.syncHandlerStats.IncLeafsRequest() +} + +func (h *handlerStats) IncInvalidLeafsRequest() { + h.syncHandlerStats.IncInvalidLeafsRequest() +} + +func (h *handlerStats) UpdateLeafsReturned(numLeafs uint16) { + h.syncHandlerStats.UpdateLeafsReturned(numLeafs) +} + +func (h *handlerStats) UpdateLeafsRequestProcessingTime(duration time.Duration) { + h.syncHandlerStats.UpdateLeafsRequestProcessingTime(duration) +} + +func (h *handlerStats) UpdateReadLeafsTime(duration time.Duration) { + h.syncHandlerStats.UpdateReadLeafsTime(duration) +} + +func (h *handlerStats) UpdateSnapshotReadTime(duration time.Duration) { + h.syncHandlerStats.UpdateSnapshotReadTime(duration) +} + +func (h *handlerStats) UpdateGenerateRangeProofTime(duration time.Duration) { + h.syncHandlerStats.UpdateGenerateRangeProofTime(duration) +} + +func (h *handlerStats) UpdateRangeProofValsReturned(numProofVals int64) { + h.syncHandlerStats.UpdateRangeProofValsReturned(numProofVals) +} + +func (h *handlerStats) IncMissingRoot() { + h.syncHandlerStats.IncMissingRoot() +} + +func (h *handlerStats) IncTrieError() { + h.syncHandlerStats.IncTrieError() +} + +func (h *handlerStats) IncProofError() { + h.syncHandlerStats.IncProofError() +} + +func (h *handlerStats) IncSnapshotReadError() { + h.syncHandlerStats.IncSnapshotReadError() +} + +func (h *handlerStats) IncSnapshotReadAttempt() { + h.syncHandlerStats.IncSnapshotReadAttempt() +} + +func (h *handlerStats) IncSnapshotReadSuccess() { + h.syncHandlerStats.IncSnapshotReadSuccess() +} + +func (h *handlerStats) IncSnapshotSegmentValid() { + h.syncHandlerStats.IncSnapshotSegmentValid() +} + +func (h *handlerStats) IncSnapshotSegmentInvalid() { + h.syncHandlerStats.IncSnapshotSegmentInvalid() +} + +func (h *handlerStats) IncSignatureRequest() { h.signatureRequest.Inc(1) } +func (h *handlerStats) IncSignatureHit() { h.signatureHit.Inc(1) } +func (h *handlerStats) IncSignatureMiss() { h.signatureMiss.Inc(1) } +func (h *handlerStats) UpdateSignatureRequestTime(duration time.Duration) { + h.signatureProcessingTime.Update(duration) +} + +func NewHandlerStats(enabled bool, syncHandlerStats syncStats.HandlerStats) HandlerStats { + if !enabled { + return NewNoopHandlerStats() + } + return &handlerStats{ + syncHandlerStats: syncHandlerStats, + + // initialize signature request stats + signatureRequest: metrics.GetOrRegisterCounter("signature_request_count", nil), + signatureHit: metrics.GetOrRegisterCounter("signature_request_hit", nil), + signatureMiss: metrics.GetOrRegisterCounter("signature_request_miss", nil), + signatureProcessingTime: metrics.GetOrRegisterTimer("signature_request_duration", nil), + } +} + +// no op implementation +type noopHandlerStats struct { + syncHandlerStats syncStats.HandlerStats +} + +func NewNoopHandlerStats() HandlerStats { + return &noopHandlerStats{ + syncHandlerStats: syncStats.NewNoopHandlerStats(), + } +} + +func (m *noopHandlerStats) IncBlockRequest() { + m.syncHandlerStats.IncBlockRequest() +} + +func (m *noopHandlerStats) IncMissingBlockHash() { + m.syncHandlerStats.IncMissingBlockHash() +} + +func (m *noopHandlerStats) UpdateBlocksReturned(num uint16) { + m.syncHandlerStats.UpdateBlocksReturned(num) +} + +func (m *noopHandlerStats) UpdateBlockRequestProcessingTime(duration time.Duration) { + m.syncHandlerStats.UpdateBlockRequestProcessingTime(duration) +} + +func (m *noopHandlerStats) IncCodeRequest() { + m.syncHandlerStats.IncCodeRequest() +} + +func (m *noopHandlerStats) IncMissingCodeHash() { + m.syncHandlerStats.IncMissingCodeHash() +} + +func (m *noopHandlerStats) IncTooManyHashesRequested() { + m.syncHandlerStats.IncTooManyHashesRequested() +} + +func (m *noopHandlerStats) IncDuplicateHashesRequested() { + m.syncHandlerStats.IncDuplicateHashesRequested() +} + +func (m *noopHandlerStats) UpdateCodeReadTime(duration time.Duration) { + m.syncHandlerStats.UpdateCodeReadTime(duration) +} + +func (m *noopHandlerStats) UpdateCodeBytesReturned(bytes uint32) { + m.syncHandlerStats.UpdateCodeBytesReturned(bytes) +} + +func (m *noopHandlerStats) IncLeafsRequest() { + m.syncHandlerStats.IncLeafsRequest() +} + +func (m *noopHandlerStats) IncInvalidLeafsRequest() { + m.syncHandlerStats.IncInvalidLeafsRequest() +} + +func (m *noopHandlerStats) UpdateLeafsReturned(numLeafs uint16) { + m.syncHandlerStats.UpdateLeafsReturned(numLeafs) +} + +func (m *noopHandlerStats) UpdateLeafsRequestProcessingTime(duration time.Duration) { + m.syncHandlerStats.UpdateLeafsRequestProcessingTime(duration) +} + +func (m *noopHandlerStats) UpdateReadLeafsTime(duration time.Duration) { + m.syncHandlerStats.UpdateReadLeafsTime(duration) +} + +func (m *noopHandlerStats) UpdateSnapshotReadTime(duration time.Duration) { + m.syncHandlerStats.UpdateSnapshotReadTime(duration) +} + +func (m *noopHandlerStats) UpdateGenerateRangeProofTime(duration time.Duration) { + m.syncHandlerStats.UpdateGenerateRangeProofTime(duration) +} + +func (m *noopHandlerStats) UpdateRangeProofValsReturned(numProofVals int64) { + m.syncHandlerStats.UpdateRangeProofValsReturned(numProofVals) +} + +func (m *noopHandlerStats) IncMissingRoot() { + m.syncHandlerStats.IncMissingRoot() +} + +func (m *noopHandlerStats) IncTrieError() { + m.syncHandlerStats.IncTrieError() +} + +func (m *noopHandlerStats) IncProofError() { + m.syncHandlerStats.IncProofError() +} + +func (m *noopHandlerStats) IncSnapshotReadError() { + m.syncHandlerStats.IncSnapshotReadError() +} + +func (m *noopHandlerStats) IncSnapshotReadAttempt() { + m.syncHandlerStats.IncSnapshotReadAttempt() +} + +func (m *noopHandlerStats) IncSnapshotReadSuccess() { + m.syncHandlerStats.IncSnapshotReadSuccess() +} + +func (m *noopHandlerStats) IncSnapshotSegmentValid() { + m.syncHandlerStats.IncSnapshotSegmentValid() +} + +func (m *noopHandlerStats) IncSnapshotSegmentInvalid() { + m.syncHandlerStats.IncSnapshotSegmentInvalid() +} + +func (m *noopHandlerStats) IncSignatureRequest() {} +func (m *noopHandlerStats) IncSignatureHit() {} +func (m *noopHandlerStats) IncSignatureMiss() {} +func (m *noopHandlerStats) UpdateSignatureRequestTime(duration time.Duration) {} diff --git a/plugin/evm/message/handler.go b/plugin/evm/message/handler.go index 2444e1ebb6..659908aaee 100644 --- a/plugin/evm/message/handler.go +++ b/plugin/evm/message/handler.go @@ -36,7 +36,7 @@ func (NoopMempoolGossipHandler) HandleTxs(nodeID ids.NodeID, _ TxsGossip) error // Also see GossipHandler for implementation style. type RequestHandler interface { HandleTrieLeafsRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, leafsRequest LeafsRequest) ([]byte, error) - HandleBlockRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, request BlockRequest) ([]byte, error) + HandleBlockRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, blockRequest BlockRequest) ([]byte, error) HandleCodeRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, codeRequest CodeRequest) ([]byte, error) HandleSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest SignatureRequest) ([]byte, error) } diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index cc08501e2b..c2e82fec04 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -16,6 +16,7 @@ import ( "time" avalanchegoMetrics "github.com/ava-labs/avalanchego/api/metrics" + "github.com/ava-labs/subnet-evm/handlers" "github.com/prometheus/client_golang/prometheus" "github.com/ava-labs/subnet-evm/commontype" @@ -35,8 +36,6 @@ import ( "github.com/ava-labs/subnet-evm/rpc" statesyncclient "github.com/ava-labs/subnet-evm/sync/client" "github.com/ava-labs/subnet-evm/sync/client/stats" - "github.com/ava-labs/subnet-evm/sync/handlers" - handlerstats "github.com/ava-labs/subnet-evm/sync/handlers/stats" "github.com/ava-labs/subnet-evm/trie" // Force-load tracer engine to trigger registration @@ -607,13 +606,9 @@ func (vm *VM) setAppRequestHandlers() { Cache: vm.config.StateSyncServerTrieCache, }, ) - syncRequestHandler := handlers.NewSyncHandler( - vm.blockChain, - evmTrieDB, - vm.networkCodec, - handlerstats.NewHandlerStats(metrics.Enabled), - ) - vm.Network.SetRequestHandler(syncRequestHandler) + + networkHandler := handlers.NewNetworkHandler(vm.blockChain, evmTrieDB, vm.networkCodec) + vm.Network.SetRequestHandler(networkHandler) } // setCrossChainAppRequestHandler sets the request handlers for the VM to serve cross chain diff --git a/sync/handlers/handler.go b/sync/handlers/handler.go index 2515428587..867941aa83 100644 --- a/sync/handlers/handler.go +++ b/sync/handlers/handler.go @@ -4,22 +4,11 @@ package handlers import ( - "context" - - "github.com/ava-labs/subnet-evm/handlers" - - "github.com/ava-labs/avalanchego/codec" - "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/subnet-evm/core/state/snapshot" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/plugin/evm/message" - "github.com/ava-labs/subnet-evm/sync/handlers/stats" - "github.com/ava-labs/subnet-evm/trie" "github.com/ethereum/go-ethereum/common" ) -var _ message.RequestHandler = &syncHandler{} - type BlockProvider interface { GetBlock(common.Hash, uint64) *types.Block } @@ -32,43 +21,3 @@ type SyncDataProvider interface { BlockProvider SnapshotProvider } - -type syncHandler struct { - stateTrieLeafsRequestHandler *LeafsRequestHandler - blockRequestHandler *BlockRequestHandler - codeRequestHandler *CodeRequestHandler - signatureRequestHandler handlers.SignatureRequestHandler -} - -// NewSyncHandler constructs the handler for serving state sync. -func NewSyncHandler( - provider SyncDataProvider, - evmTrieDB *trie.Database, - networkCodec codec.Manager, - stats stats.HandlerStats, -) message.RequestHandler { - return &syncHandler{ - stateTrieLeafsRequestHandler: NewLeafsRequestHandler(evmTrieDB, provider, networkCodec, stats), - blockRequestHandler: NewBlockRequestHandler(provider, networkCodec, stats), - codeRequestHandler: NewCodeRequestHandler(evmTrieDB.DiskDB(), networkCodec, stats), - - // TODO: initialize actual signature request handler when warp is ready - signatureRequestHandler: &handlers.NoopSignatureRequestHandler{}, - } -} - -func (s *syncHandler) HandleTrieLeafsRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, leafsRequest message.LeafsRequest) ([]byte, error) { - return s.stateTrieLeafsRequestHandler.OnLeafsRequest(ctx, nodeID, requestID, leafsRequest) -} - -func (s *syncHandler) HandleBlockRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, blockRequest message.BlockRequest) ([]byte, error) { - return s.blockRequestHandler.OnBlockRequest(ctx, nodeID, requestID, blockRequest) -} - -func (s *syncHandler) HandleCodeRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, codeRequest message.CodeRequest) ([]byte, error) { - return s.codeRequestHandler.OnCodeRequest(ctx, nodeID, requestID, codeRequest) -} - -func (s *syncHandler) HandleSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) { - return s.signatureRequestHandler.OnSignatureRequest(ctx, nodeID, requestID, signatureRequest) -} diff --git a/sync/handlers/stats/mock_stats.go b/sync/handlers/stats/mock_stats.go index 407b1c4b7b..59d2433172 100644 --- a/sync/handlers/stats/mock_stats.go +++ b/sync/handlers/stats/mock_stats.go @@ -42,11 +42,6 @@ type MockHandlerStats struct { SnapshotReadTime, GenerateRangeProofTime, LeafRequestProcessingTimeSum time.Duration - - SignatureRequestCount, - SignatureRequestHit, - SignatureRequestMiss uint32 - SignatureRequestDuration time.Duration } func (m *MockHandlerStats) Reset() { @@ -78,10 +73,6 @@ func (m *MockHandlerStats) Reset() { m.SnapshotReadTime = 0 m.GenerateRangeProofTime = 0 m.LeafRequestProcessingTimeSum = 0 - m.SignatureRequestCount = 0 - m.SignatureRequestHit = 0 - m.SignatureRequestMiss = 0 - m.SignatureRequestDuration = 0 } func (m *MockHandlerStats) IncBlockRequest() { @@ -239,27 +230,3 @@ func (m *MockHandlerStats) IncSnapshotSegmentInvalid() { defer m.lock.Unlock() m.SnapshotSegmentInvalidCount++ } - -func (m *MockHandlerStats) IncSignatureRequest() { - m.lock.Lock() - defer m.lock.Unlock() - m.SignatureRequestCount++ -} - -func (m *MockHandlerStats) IncSignatureHit() { - m.lock.Lock() - defer m.lock.Unlock() - m.SignatureRequestHit++ -} - -func (m *MockHandlerStats) IncSignatureMiss() { - m.lock.Lock() - defer m.lock.Unlock() - m.SignatureRequestMiss++ -} - -func (m *MockHandlerStats) UpdateSignatureRequestTime(duration time.Duration) { - m.lock.Lock() - defer m.lock.Unlock() - m.SignatureRequestDuration += duration -} diff --git a/sync/handlers/stats/stats.go b/sync/handlers/stats/stats.go index 1d61de0034..6d19b62a86 100644 --- a/sync/handlers/stats/stats.go +++ b/sync/handlers/stats/stats.go @@ -14,7 +14,6 @@ type HandlerStats interface { BlockRequestHandlerStats CodeRequestHandlerStats LeafsRequestHandlerStats - SignatureRequestHandlerStats } type BlockRequestHandlerStats interface { @@ -52,13 +51,6 @@ type LeafsRequestHandlerStats interface { IncSnapshotSegmentInvalid() } -type SignatureRequestHandlerStats interface { - IncSignatureRequest() - IncSignatureHit() - IncSignatureMiss() - UpdateSignatureRequestTime(duration time.Duration) -} - type handlerStats struct { // BlockRequestHandler metrics blockRequest metrics.Counter @@ -91,12 +83,6 @@ type handlerStats struct { snapshotReadSuccess metrics.Counter snapshotSegmentValid metrics.Counter snapshotSegmentInvalid metrics.Counter - - // SignatureRequestHandler metrics - signatureRequest metrics.Counter - signatureHit metrics.Counter - signatureMiss metrics.Counter - signatureProcessingTime metrics.Timer } func (h *handlerStats) IncBlockRequest() { @@ -180,13 +166,6 @@ func (h *handlerStats) IncSnapshotReadSuccess() { h.snapshotReadSuccess.Inc(1 func (h *handlerStats) IncSnapshotSegmentValid() { h.snapshotSegmentValid.Inc(1) } func (h *handlerStats) IncSnapshotSegmentInvalid() { h.snapshotSegmentInvalid.Inc(1) } -func (h *handlerStats) IncSignatureRequest() { h.signatureRequest.Inc(1) } -func (h *handlerStats) IncSignatureHit() { h.signatureHit.Inc(1) } -func (h *handlerStats) IncSignatureMiss() { h.signatureMiss.Inc(1) } -func (h *handlerStats) UpdateSignatureRequestTime(duration time.Duration) { - h.signatureProcessingTime.Update(duration) -} - func NewHandlerStats(enabled bool) HandlerStats { if !enabled { return NewNoopHandlerStats() @@ -223,12 +202,6 @@ func NewHandlerStats(enabled bool) HandlerStats { snapshotReadSuccess: metrics.GetOrRegisterCounter("leafs_request_snapshot_read_success", nil), snapshotSegmentValid: metrics.GetOrRegisterCounter("leafs_request_snapshot_segment_valid", nil), snapshotSegmentInvalid: metrics.GetOrRegisterCounter("leafs_request_snapshot_segment_invalid", nil), - - // initialize signature request stats - signatureRequest: metrics.GetOrRegisterCounter("signature_request_count", nil), - signatureHit: metrics.GetOrRegisterCounter("signature_request_hit", nil), - signatureMiss: metrics.GetOrRegisterCounter("signature_request_miss", nil), - signatureProcessingTime: metrics.GetOrRegisterTimer("signature_request_duration", nil), } } @@ -266,7 +239,3 @@ func (n *noopHandlerStats) IncSnapshotReadAttempt() func (n *noopHandlerStats) IncSnapshotReadSuccess() {} func (n *noopHandlerStats) IncSnapshotSegmentValid() {} func (n *noopHandlerStats) IncSnapshotSegmentInvalid() {} -func (n *noopHandlerStats) IncSignatureRequest() {} -func (n *noopHandlerStats) IncSignatureHit() {} -func (n *noopHandlerStats) IncSignatureMiss() {} -func (n *noopHandlerStats) UpdateSignatureRequestTime(duration time.Duration) {} From cfd843e732fb1f6d37d5951bc9d0eed789378faf Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Thu, 2 Feb 2023 15:52:25 -0800 Subject: [PATCH 39/50] change constructor of handler stats --- handlers/handler.go | 4 +--- handlers/stats/stats.go | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/handlers/handler.go b/handlers/handler.go index c1afb37438..ee62d5bcb2 100644 --- a/handlers/handler.go +++ b/handlers/handler.go @@ -13,7 +13,6 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/sync/handlers" - syncStats "github.com/ava-labs/subnet-evm/sync/handlers/stats" "github.com/ava-labs/subnet-evm/trie" ) @@ -31,8 +30,7 @@ func NewNetworkHandler( evmTrieDB *trie.Database, networkCodec codec.Manager, ) message.RequestHandler { - syncStats := syncStats.NewHandlerStats(metrics.Enabled) - handlerStats := stats.NewHandlerStats(metrics.Enabled, syncStats) + handlerStats := stats.NewHandlerStats(metrics.Enabled) return &networkHandler{ stateTrieLeafsRequestHandler: handlers.NewLeafsRequestHandler(evmTrieDB, provider, networkCodec, handlerStats), blockRequestHandler: handlers.NewBlockRequestHandler(provider, networkCodec, handlerStats), diff --git a/handlers/stats/stats.go b/handlers/stats/stats.go index 3de14b06c3..c37f597e3b 100644 --- a/handlers/stats/stats.go +++ b/handlers/stats/stats.go @@ -149,12 +149,12 @@ func (h *handlerStats) UpdateSignatureRequestTime(duration time.Duration) { h.signatureProcessingTime.Update(duration) } -func NewHandlerStats(enabled bool, syncHandlerStats syncStats.HandlerStats) HandlerStats { +func NewHandlerStats(enabled bool) HandlerStats { if !enabled { return NewNoopHandlerStats() } return &handlerStats{ - syncHandlerStats: syncHandlerStats, + syncHandlerStats: syncStats.NewHandlerStats(enabled), // initialize signature request stats signatureRequest: metrics.GetOrRegisterCounter("signature_request_count", nil), From 4b636e97a2555ad59823d9004cbe12885eb458f2 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Thu, 2 Feb 2023 15:57:54 -0800 Subject: [PATCH 40/50] pr cleanups --- handlers/handler.go | 18 ++++++++++-------- handlers/stats/stats.go | 2 ++ plugin/evm/warp/backend.go | 3 +-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/handlers/handler.go b/handlers/handler.go index ee62d5bcb2..79eff82d70 100644 --- a/handlers/handler.go +++ b/handlers/handler.go @@ -7,24 +7,25 @@ import ( "context" "github.com/ava-labs/avalanchego/codec" + "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/subnet-evm/handlers/stats" "github.com/ava-labs/subnet-evm/metrics" - - "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/sync/handlers" + syncHandlers "github.com/ava-labs/subnet-evm/sync/handlers" "github.com/ava-labs/subnet-evm/trie" ) var _ message.RequestHandler = &networkHandler{} type networkHandler struct { - stateTrieLeafsRequestHandler *handlers.LeafsRequestHandler - blockRequestHandler *handlers.BlockRequestHandler - codeRequestHandler *handlers.CodeRequestHandler + stateTrieLeafsRequestHandler *syncHandlers.LeafsRequestHandler + blockRequestHandler *syncHandlers.BlockRequestHandler + codeRequestHandler *syncHandlers.CodeRequestHandler signatureRequestHandler SignatureRequestHandler } +// NewNetworkHandler constructs the handler for serving network requests. func NewNetworkHandler( provider handlers.SyncDataProvider, evmTrieDB *trie.Database, @@ -32,9 +33,10 @@ func NewNetworkHandler( ) message.RequestHandler { handlerStats := stats.NewHandlerStats(metrics.Enabled) return &networkHandler{ - stateTrieLeafsRequestHandler: handlers.NewLeafsRequestHandler(evmTrieDB, provider, networkCodec, handlerStats), - blockRequestHandler: handlers.NewBlockRequestHandler(provider, networkCodec, handlerStats), - codeRequestHandler: handlers.NewCodeRequestHandler(evmTrieDB.DiskDB(), networkCodec, handlerStats), + // State sync handlers + stateTrieLeafsRequestHandler: syncHandlers.NewLeafsRequestHandler(evmTrieDB, provider, networkCodec, handlerStats), + blockRequestHandler: syncHandlers.NewBlockRequestHandler(provider, networkCodec, handlerStats), + codeRequestHandler: syncHandlers.NewCodeRequestHandler(evmTrieDB.DiskDB(), networkCodec, handlerStats), // TODO: initialize actual signature request handler when warp is ready signatureRequestHandler: &NoopSignatureRequestHandler{}, diff --git a/handlers/stats/stats.go b/handlers/stats/stats.go index c37f597e3b..946027a910 100644 --- a/handlers/stats/stats.go +++ b/handlers/stats/stats.go @@ -29,6 +29,7 @@ type SignatureRequestHandlerStats interface { } type handlerStats struct { + // State sync metrics syncHandlerStats syncStats.HandlerStats // SignatureRequestHandler metrics @@ -154,6 +155,7 @@ func NewHandlerStats(enabled bool) HandlerStats { return NewNoopHandlerStats() } return &handlerStats{ + // initialize state sync handler stats syncHandlerStats: syncStats.NewHandlerStats(enabled), // initialize signature request stats diff --git a/plugin/evm/warp/backend.go b/plugin/evm/warp/backend.go index 927dae7ea2..7aade1514d 100644 --- a/plugin/evm/warp/backend.go +++ b/plugin/evm/warp/backend.go @@ -7,12 +7,11 @@ import ( "context" "fmt" - "github.com/ava-labs/avalanchego/utils/crypto/bls" - "github.com/ava-labs/avalanchego/cache" "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/vms/platformvm/teleporter" ) From 9755d4f4137851e81bed37dad847a0dfb4c05c5a Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Mon, 6 Feb 2023 16:15:55 +0000 Subject: [PATCH 41/50] warp api --- plugin/evm/client.go | 15 ++------ plugin/evm/config.go | 1 + plugin/evm/{service.go => snowman_service.go} | 18 +-------- plugin/evm/vm.go | 7 ++++ plugin/evm/warp_client.go | 38 +++++++++++++++++++ plugin/evm/warp_service.go | 29 ++++++++++++++ 6 files changed, 79 insertions(+), 29 deletions(-) rename plugin/evm/{service.go => snowman_service.go} (63%) create mode 100644 plugin/evm/warp_client.go create mode 100644 plugin/evm/warp_service.go diff --git a/plugin/evm/client.go b/plugin/evm/client.go index 72f3e080c9..78e55d73f4 100644 --- a/plugin/evm/client.go +++ b/plugin/evm/client.go @@ -8,9 +8,7 @@ import ( "fmt" "github.com/ava-labs/avalanchego/api" - "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/rpc" - "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ethereum/go-ethereum/log" ) @@ -25,7 +23,6 @@ type Client interface { LockProfile(ctx context.Context) error SetLogLevel(ctx context.Context, level log.Lvl) error GetVMConfig(ctx context.Context) (*Config, error) - GetSignature(ctx context.Context, signatureRequest message.SignatureRequest) (*[bls.SignatureLen]byte, error) } // Client implementation for interacting with EVM [chain] @@ -34,16 +31,16 @@ type client struct { } // NewClient returns a Client for interacting with EVM [chain] -func NewClient(uri, chain, api string) Client { +func NewClient(uri, chain string) Client { return &client{ - requester: rpc.NewEndpointRequester(fmt.Sprintf("%s/ext/bc/%s/%s", uri, chain, api)), + requester: rpc.NewEndpointRequester(fmt.Sprintf("%s/ext/bc/%s/admin", uri, chain)), } } // NewCChainClient returns a Client for interacting with the C Chain func NewCChainClient(uri string) Client { // TODO: Update for Subnet-EVM compatibility - return NewClient(uri, "C", "admin") + return NewClient(uri, "C") } func (c *client) StartCPUProfiler(ctx context.Context) error { @@ -75,9 +72,3 @@ func (c *client) GetVMConfig(ctx context.Context) (*Config, error) { err := c.requester.SendRequest(ctx, "admin.getVMConfig", struct{}{}, res) return res.Config, err } - -func (c *client) GetSignature(ctx context.Context, signatureRequest message.SignatureRequest) (*[bls.SignatureLen]byte, error) { - res := &message.SignatureResponse{} - err := c.requester.SendRequest(ctx, "snowman.getSignature", &signatureRequest, res) - return &res.Signature, err -} diff --git a/plugin/evm/config.go b/plugin/evm/config.go index fcb0fa297c..6abaed1093 100644 --- a/plugin/evm/config.go +++ b/plugin/evm/config.go @@ -84,6 +84,7 @@ type Config struct { // Subnet EVM APIs SnowmanAPIEnabled bool `json:"snowman-api-enabled"` + WarpAPIEnabled bool `json:"warp-api-enabled"` AdminAPIEnabled bool `json:"admin-api-enabled"` AdminAPIDir string `json:"admin-api-dir"` diff --git a/plugin/evm/service.go b/plugin/evm/snowman_service.go similarity index 63% rename from plugin/evm/service.go rename to plugin/evm/snowman_service.go index 64b241b75c..d4113ce203 100644 --- a/plugin/evm/service.go +++ b/plugin/evm/snowman_service.go @@ -1,4 +1,4 @@ -// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// (c) 2019-2023, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. package evm @@ -7,8 +7,6 @@ import ( "context" "math/big" - "github.com/ava-labs/avalanchego/utils/crypto/bls" - "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" ) @@ -45,17 +43,3 @@ func (api *SnowmanAPI) IssueBlock(ctx context.Context) error { api.vm.builder.signalTxsReady() return nil } - -func (api *SnowmanAPI) GetSignature(ctx context.Context, signatureRequest *message.SignatureRequest) (*message.SignatureResponse, error) { - sig, err := api.vm.backend.GetSignature(ctx, signatureRequest.MessageID) - if err != nil { - log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) - return nil, nil - } - var signature [bls.SignatureLen]byte - copy(signature[:], sig) - response := message.SignatureResponse{ - Signature: signature, - } - return &response, nil -} diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index f87486e575..fe1426977f 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -805,6 +805,13 @@ func (vm *VM) CreateHandlers(context.Context) (map[string]*commonEng.HTTPHandler enabledAPIs = append(enabledAPIs, "snowman") } + if vm.config.WarpAPIEnabled { + if err := handler.RegisterName("warp", &WarpAPI{vm}); err != nil { + return nil, err + } + enabledAPIs = append(enabledAPIs, "warp") + } + log.Info(fmt.Sprintf("Enabled APIs: %s", strings.Join(enabledAPIs, ", "))) apis[ethRPCEndpoint] = &commonEng.HTTPHandler{ LockOptions: commonEng.NoLock, diff --git a/plugin/evm/warp_client.go b/plugin/evm/warp_client.go new file mode 100644 index 0000000000..a1e1678c47 --- /dev/null +++ b/plugin/evm/warp_client.go @@ -0,0 +1,38 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package evm + +import ( + "context" + "fmt" + + "github.com/ava-labs/avalanchego/utils/crypto/bls" + "github.com/ava-labs/avalanchego/utils/rpc" + "github.com/ava-labs/subnet-evm/plugin/evm/message" +) + +// Interface compliance +var _ WarpClient = (*warpClient)(nil) + +type WarpClient interface { + GetSignature(ctx context.Context, signatureRequest message.SignatureRequest) (*[bls.SignatureLen]byte, error) +} + +// Client implementation for interacting with EVM [chain] +type warpClient struct { + requester rpc.EndpointRequester +} + +// NewClient returns a Client for interacting with EVM [chain] +func NewWarpClient(uri, chain string) WarpClient { + return &warpClient{ + requester: rpc.NewEndpointRequester(fmt.Sprintf("%s/ext/bc/%s/warp", uri, chain)), + } +} + +func (c *warpClient) GetSignature(ctx context.Context, signatureRequest message.SignatureRequest) (*[bls.SignatureLen]byte, error) { + res := &message.SignatureResponse{} + err := c.requester.SendRequest(ctx, "warp.getSignature", &signatureRequest, res) + return &res.Signature, err +} diff --git a/plugin/evm/warp_service.go b/plugin/evm/warp_service.go new file mode 100644 index 0000000000..e12aab511e --- /dev/null +++ b/plugin/evm/warp_service.go @@ -0,0 +1,29 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package evm + +import ( + "context" + + "github.com/ava-labs/avalanchego/utils/crypto/bls" + "github.com/ava-labs/subnet-evm/plugin/evm/message" + "github.com/ethereum/go-ethereum/log" +) + +// SnowmanAPI introduces snowman specific functionality to the evm +type WarpAPI struct{ vm *VM } + +func (api *WarpAPI) GetSignature(ctx context.Context, signatureRequest *message.SignatureRequest) (*message.SignatureResponse, error) { + sig, err := api.vm.backend.GetSignature(ctx, signatureRequest.MessageID) + if err != nil { + log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) + return nil, nil + } + var signature [bls.SignatureLen]byte + copy(signature[:], sig) + response := message.SignatureResponse{ + Signature: signature, + } + return &response, nil +} From cf5c9079ec4ccb8cfceeedc3c189a0055b1c0618 Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Mon, 6 Feb 2023 17:27:03 +0000 Subject: [PATCH 42/50] initialize warp backend --- plugin/evm/vm.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index fe1426977f..2a42f10dbe 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -87,6 +87,7 @@ const ( decidedCacheSize = 100 missingCacheSize = 50 unverifiedCacheSize = 50 + signatureCacheSize = 500 // Prefixes for metrics gatherers ethMetricsPrefix = "eth" @@ -105,6 +106,7 @@ var ( lastAcceptedKey = []byte("last_accepted_key") acceptedPrefix = []byte("snowman_accepted") metadataPrefix = []byte("metadata") + warpPrefix = []byte("warp") ethDBPrefix = []byte("ethdb") ) @@ -180,6 +182,9 @@ type VM struct { // block. acceptedBlockDB database.Database + // [warpDB] is used to store warp message signatures + warpDB database.Database + toEngine chan<- commonEng.Message syntacticBlockValidator BlockValidator @@ -280,6 +285,7 @@ func (vm *VM) Initialize( vm.db = versiondb.New(baseDB) vm.acceptedBlockDB = prefixdb.New(acceptedPrefix, vm.db) vm.metadataDB = prefixdb.New(metadataPrefix, vm.db) + vm.warpDB = prefixdb.New(warpPrefix, vm.db) if vm.config.InspectDatabase { start := time.Now() @@ -421,6 +427,9 @@ func (vm *VM) Initialize( vm.Network = peer.NewNetwork(appSender, vm.networkCodec, message.CrossChainCodec, chainCtx.NodeID, vm.config.MaxOutboundActiveRequests, vm.config.MaxOutboundActiveCrossChainRequests) vm.client = peer.NewNetworkClient(vm.Network) + // initialize warp backend + vm.backend = warp.NewWarpBackend(vm.ctx, vm.warpDB, signatureCacheSize) + if err := vm.initializeChain(lastAcceptedHash, vm.ethConfig); err != nil { return err } From fc668f9cc8c585671b168b7eb30369512097822d Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Mon, 6 Feb 2023 18:17:54 +0000 Subject: [PATCH 43/50] build fix --- plugin/evm/warp_service.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugin/evm/warp_service.go b/plugin/evm/warp_service.go index e12aab511e..9830f99321 100644 --- a/plugin/evm/warp_service.go +++ b/plugin/evm/warp_service.go @@ -6,7 +6,6 @@ package evm import ( "context" - "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ethereum/go-ethereum/log" ) @@ -15,13 +14,12 @@ import ( type WarpAPI struct{ vm *VM } func (api *WarpAPI) GetSignature(ctx context.Context, signatureRequest *message.SignatureRequest) (*message.SignatureResponse, error) { - sig, err := api.vm.backend.GetSignature(ctx, signatureRequest.MessageID) + signature, err := api.vm.backend.GetSignature(ctx, signatureRequest.MessageID) if err != nil { log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) return nil, nil } - var signature [bls.SignatureLen]byte - copy(signature[:], sig) + response := message.SignatureResponse{ Signature: signature, } From dfcc95e6c496e017f82f4c1227be7e11722d7e96 Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Tue, 7 Feb 2023 16:22:50 +0000 Subject: [PATCH 44/50] wip --- plugin/evm/vm.go | 6 +++--- plugin/evm/warp_client.go | 8 ++++++-- plugin/evm/warp_service.go | 21 ++++++++++++++++++--- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 10f3fc9924..49936f1ef9 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -793,7 +793,7 @@ func (vm *VM) CreateHandlers(context.Context) (map[string]*commonEng.HTTPHandler return nil, fmt.Errorf("failed to get primary alias for chain due to %w", err) } apis := make(map[string]*commonEng.HTTPHandler) - if vm.config.AdminAPIEnabled { + if true { //vm.config.AdminAPIEnabled { adminAPI, err := newHandler("admin", NewAdminService(vm, os.ExpandEnv(fmt.Sprintf("%s_subnet_evm_performance_%s", vm.config.AdminAPIDir, primaryAlias)))) if err != nil { return nil, fmt.Errorf("failed to register service for admin API due to %w", err) @@ -802,14 +802,14 @@ func (vm *VM) CreateHandlers(context.Context) (map[string]*commonEng.HTTPHandler enabledAPIs = append(enabledAPIs, "subnet-evm-admin") } - if vm.config.SnowmanAPIEnabled { + if true { //vm.config.SnowmanAPIEnabled { if err := handler.RegisterName("snowman", &SnowmanAPI{vm}); err != nil { return nil, err } enabledAPIs = append(enabledAPIs, "snowman") } - if vm.config.WarpAPIEnabled { + if true { //vm.config.WarpAPIEnabled { if err := handler.RegisterName("warp", &WarpAPI{vm}); err != nil { return nil, err } diff --git a/plugin/evm/warp_client.go b/plugin/evm/warp_client.go index a1e1678c47..3563d581c6 100644 --- a/plugin/evm/warp_client.go +++ b/plugin/evm/warp_client.go @@ -5,6 +5,7 @@ package evm import ( "context" + "encoding/hex" "fmt" "github.com/ava-labs/avalanchego/utils/crypto/bls" @@ -27,12 +28,15 @@ type warpClient struct { // NewClient returns a Client for interacting with EVM [chain] func NewWarpClient(uri, chain string) WarpClient { return &warpClient{ - requester: rpc.NewEndpointRequester(fmt.Sprintf("%s/ext/bc/%s/warp", uri, chain)), + requester: rpc.NewEndpointRequester(fmt.Sprintf("%s/ext/bc/%s/rpc", uri, chain)), } } func (c *warpClient) GetSignature(ctx context.Context, signatureRequest message.SignatureRequest) (*[bls.SignatureLen]byte, error) { + sigReqJson := SignatureRequest{ + MessageID: hex.EncodeToString(signatureRequest.MessageID[:]), + } res := &message.SignatureResponse{} - err := c.requester.SendRequest(ctx, "warp.getSignature", &signatureRequest, res) + err := c.requester.SendRequest(ctx, "warp_getSignature", &sigReqJson, res) return &res.Signature, err } diff --git a/plugin/evm/warp_service.go b/plugin/evm/warp_service.go index 9830f99321..051a9ba3be 100644 --- a/plugin/evm/warp_service.go +++ b/plugin/evm/warp_service.go @@ -5,16 +5,31 @@ package evm import ( "context" + "encoding/hex" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ethereum/go-ethereum/log" ) -// SnowmanAPI introduces snowman specific functionality to the evm +const ( + MessageIDLength = 32 +) + +// WarpAPI introduces snowman specific functionality to the evm type WarpAPI struct{ vm *VM } -func (api *WarpAPI) GetSignature(ctx context.Context, signatureRequest *message.SignatureRequest) (*message.SignatureResponse, error) { - signature, err := api.vm.backend.GetSignature(ctx, signatureRequest.MessageID) +type SignatureRequest struct { + MessageID string `json:"messageID"` +} + +func (api *WarpAPI) GetSignature(ctx context.Context, signatureRequest *SignatureRequest) (*message.SignatureResponse, error) { + sigReqBytes, err := hex.DecodeString(signatureRequest.MessageID) + if err != nil || len(sigReqBytes) != MessageIDLength { + log.Info("Invalid messageID hex in signature request") + return nil, err + } + + signature, err := api.vm.backend.GetSignature(ctx, *(*[32]byte)(sigReqBytes)) if err != nil { log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) return nil, nil From cfcb650a32d2f437f56d04a746600003ff302b6a Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Tue, 7 Feb 2023 18:38:44 +0000 Subject: [PATCH 45/50] warp api follows eth api pattern --- plugin/evm/warp_client.go | 34 ++++++++++++++++++++++++---------- plugin/evm/warp_service.go | 22 ++++------------------ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/plugin/evm/warp_client.go b/plugin/evm/warp_client.go index 3563d581c6..9190448d23 100644 --- a/plugin/evm/warp_client.go +++ b/plugin/evm/warp_client.go @@ -5,12 +5,14 @@ package evm import ( "context" - "encoding/hex" "fmt" + "github.com/ava-labs/subnet-evm/rpc" + + "github.com/ava-labs/avalanchego/utils/cb58" "github.com/ava-labs/avalanchego/utils/crypto/bls" - "github.com/ava-labs/avalanchego/utils/rpc" "github.com/ava-labs/subnet-evm/plugin/evm/message" + "github.com/ethereum/go-ethereum/log" ) // Interface compliance @@ -22,21 +24,33 @@ type WarpClient interface { // Client implementation for interacting with EVM [chain] type warpClient struct { - requester rpc.EndpointRequester + client *rpc.Client } // NewClient returns a Client for interacting with EVM [chain] -func NewWarpClient(uri, chain string) WarpClient { - return &warpClient{ - requester: rpc.NewEndpointRequester(fmt.Sprintf("%s/ext/bc/%s/rpc", uri, chain)), +func NewWarpClient(uri, chain string) (WarpClient, error) { + client, err := rpc.Dial(fmt.Sprintf("%s/ext/bc/%s/rpc", uri, chain)) + if err != nil { + log.Error("failed to dial client") + return nil, err } + return &warpClient{ + client: client, + }, nil } func (c *warpClient) GetSignature(ctx context.Context, signatureRequest message.SignatureRequest) (*[bls.SignatureLen]byte, error) { - sigReqJson := SignatureRequest{ - MessageID: hex.EncodeToString(signatureRequest.MessageID[:]), + req, err := cb58.Encode(signatureRequest.MessageID[:]) + if err != nil { + log.Info("failed to base58 encode the request", "messageID", signatureRequest.MessageID) + return nil, err + } + + var res message.SignatureResponse + err = c.client.CallContext(ctx, &res, "warp_getSignature", req) + if err != nil { + log.Info("call to warp_getSignature failed", "err", err) + return nil, err } - res := &message.SignatureResponse{} - err := c.requester.SendRequest(ctx, "warp_getSignature", &sigReqJson, res) return &res.Signature, err } diff --git a/plugin/evm/warp_service.go b/plugin/evm/warp_service.go index 051a9ba3be..36a2bd6644 100644 --- a/plugin/evm/warp_service.go +++ b/plugin/evm/warp_service.go @@ -5,33 +5,19 @@ package evm import ( "context" - "encoding/hex" + "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ethereum/go-ethereum/log" ) -const ( - MessageIDLength = 32 -) - // WarpAPI introduces snowman specific functionality to the evm type WarpAPI struct{ vm *VM } -type SignatureRequest struct { - MessageID string `json:"messageID"` -} - -func (api *WarpAPI) GetSignature(ctx context.Context, signatureRequest *SignatureRequest) (*message.SignatureResponse, error) { - sigReqBytes, err := hex.DecodeString(signatureRequest.MessageID) - if err != nil || len(sigReqBytes) != MessageIDLength { - log.Info("Invalid messageID hex in signature request") - return nil, err - } - - signature, err := api.vm.backend.GetSignature(ctx, *(*[32]byte)(sigReqBytes)) +func (api *WarpAPI) GetSignature(ctx context.Context, messageID ids.ID) (*message.SignatureResponse, error) { + signature, err := api.vm.backend.GetSignature(ctx, messageID) if err != nil { - log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) + log.Debug("Unknown warp signature requested", "messageID", messageID) return nil, nil } From 0d4e895517c01a2fb32c5e8d10fc4d2545b11eba Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Tue, 7 Feb 2023 19:13:12 +0000 Subject: [PATCH 46/50] cleanup and comments --- plugin/evm/vm.go | 6 +++--- plugin/evm/warp_client.go | 5 +++-- plugin/evm/warp_service.go | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 49936f1ef9..10f3fc9924 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -793,7 +793,7 @@ func (vm *VM) CreateHandlers(context.Context) (map[string]*commonEng.HTTPHandler return nil, fmt.Errorf("failed to get primary alias for chain due to %w", err) } apis := make(map[string]*commonEng.HTTPHandler) - if true { //vm.config.AdminAPIEnabled { + if vm.config.AdminAPIEnabled { adminAPI, err := newHandler("admin", NewAdminService(vm, os.ExpandEnv(fmt.Sprintf("%s_subnet_evm_performance_%s", vm.config.AdminAPIDir, primaryAlias)))) if err != nil { return nil, fmt.Errorf("failed to register service for admin API due to %w", err) @@ -802,14 +802,14 @@ func (vm *VM) CreateHandlers(context.Context) (map[string]*commonEng.HTTPHandler enabledAPIs = append(enabledAPIs, "subnet-evm-admin") } - if true { //vm.config.SnowmanAPIEnabled { + if vm.config.SnowmanAPIEnabled { if err := handler.RegisterName("snowman", &SnowmanAPI{vm}); err != nil { return nil, err } enabledAPIs = append(enabledAPIs, "snowman") } - if true { //vm.config.WarpAPIEnabled { + if vm.config.WarpAPIEnabled { if err := handler.RegisterName("warp", &WarpAPI{vm}); err != nil { return nil, err } diff --git a/plugin/evm/warp_client.go b/plugin/evm/warp_client.go index 9190448d23..a6e6394bd8 100644 --- a/plugin/evm/warp_client.go +++ b/plugin/evm/warp_client.go @@ -22,12 +22,12 @@ type WarpClient interface { GetSignature(ctx context.Context, signatureRequest message.SignatureRequest) (*[bls.SignatureLen]byte, error) } -// Client implementation for interacting with EVM [chain] +// warpClient implementation for interacting with EVM [chain] type warpClient struct { client *rpc.Client } -// NewClient returns a Client for interacting with EVM [chain] +// NewWarpClient returns a WarpClient for interacting with EVM [chain] func NewWarpClient(uri, chain string) (WarpClient, error) { client, err := rpc.Dial(fmt.Sprintf("%s/ext/bc/%s/rpc", uri, chain)) if err != nil { @@ -39,6 +39,7 @@ func NewWarpClient(uri, chain string) (WarpClient, error) { }, nil } +// GetSignature requests the BLS signature associated with a messageID func (c *warpClient) GetSignature(ctx context.Context, signatureRequest message.SignatureRequest) (*[bls.SignatureLen]byte, error) { req, err := cb58.Encode(signatureRequest.MessageID[:]) if err != nil { diff --git a/plugin/evm/warp_service.go b/plugin/evm/warp_service.go index 36a2bd6644..db103f2492 100644 --- a/plugin/evm/warp_service.go +++ b/plugin/evm/warp_service.go @@ -14,6 +14,7 @@ import ( // WarpAPI introduces snowman specific functionality to the evm type WarpAPI struct{ vm *VM } +// GetSignature returns the BLS signature associated with a messageID. In the raw request, [messageID] should be cb58 encoded func (api *WarpAPI) GetSignature(ctx context.Context, messageID ids.ID) (*message.SignatureResponse, error) { signature, err := api.vm.backend.GetSignature(ctx, messageID) if err != nil { From cee8aa0ec3a5f64d83d2e7e173c13a6d670d79ea Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Wed, 8 Feb 2023 15:01:38 +0000 Subject: [PATCH 47/50] clean up response --- plugin/evm/warp_client.go | 10 +++------- plugin/evm/warp_service.go | 18 +++++++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/plugin/evm/warp_client.go b/plugin/evm/warp_client.go index a6e6394bd8..8cdef93500 100644 --- a/plugin/evm/warp_client.go +++ b/plugin/evm/warp_client.go @@ -12,7 +12,6 @@ import ( "github.com/ava-labs/avalanchego/utils/cb58" "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/subnet-evm/plugin/evm/message" - "github.com/ethereum/go-ethereum/log" ) // Interface compliance @@ -31,8 +30,7 @@ type warpClient struct { func NewWarpClient(uri, chain string) (WarpClient, error) { client, err := rpc.Dial(fmt.Sprintf("%s/ext/bc/%s/rpc", uri, chain)) if err != nil { - log.Error("failed to dial client") - return nil, err + return nil, fmt.Errorf("failed to dial client. err: %w", err) } return &warpClient{ client: client, @@ -43,15 +41,13 @@ func NewWarpClient(uri, chain string) (WarpClient, error) { func (c *warpClient) GetSignature(ctx context.Context, signatureRequest message.SignatureRequest) (*[bls.SignatureLen]byte, error) { req, err := cb58.Encode(signatureRequest.MessageID[:]) if err != nil { - log.Info("failed to base58 encode the request", "messageID", signatureRequest.MessageID) - return nil, err + return nil, fmt.Errorf("failed to base58 encode the request. messageID: %s, error: %w", signatureRequest.MessageID, err) } var res message.SignatureResponse err = c.client.CallContext(ctx, &res, "warp_getSignature", req) if err != nil { - log.Info("call to warp_getSignature failed", "err", err) - return nil, err + return nil, fmt.Errorf("call to warp_getSignature failed. err: %w", err) } return &res.Signature, err } diff --git a/plugin/evm/warp_service.go b/plugin/evm/warp_service.go index db103f2492..36264008d6 100644 --- a/plugin/evm/warp_service.go +++ b/plugin/evm/warp_service.go @@ -5,25 +5,29 @@ package evm import ( "context" + "fmt" "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/subnet-evm/plugin/evm/message" - "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/common/hexutil" ) +type SignatureResponse struct { + Signature hexutil.Bytes +} + // WarpAPI introduces snowman specific functionality to the evm type WarpAPI struct{ vm *VM } // GetSignature returns the BLS signature associated with a messageID. In the raw request, [messageID] should be cb58 encoded -func (api *WarpAPI) GetSignature(ctx context.Context, messageID ids.ID) (*message.SignatureResponse, error) { +func (api *WarpAPI) GetSignature(ctx context.Context, messageID ids.ID) (*SignatureResponse, error) { signature, err := api.vm.backend.GetSignature(ctx, messageID) if err != nil { - log.Debug("Unknown warp signature requested", "messageID", messageID) - return nil, nil + return nil, fmt.Errorf("failed to get signature for with error %w", err) } + sigBytes := (hexutil.Bytes)(signature[:]) - response := message.SignatureResponse{ - Signature: signature, + response := SignatureResponse{ + Signature: sigBytes, } return &response, nil } From 93a43d062b61f00b1a0cebf6d1d7c4255f7c7afd Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Wed, 8 Feb 2023 15:06:25 +0000 Subject: [PATCH 48/50] fix warp client return type --- plugin/evm/warp_client.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugin/evm/warp_client.go b/plugin/evm/warp_client.go index 8cdef93500..874ce5073d 100644 --- a/plugin/evm/warp_client.go +++ b/plugin/evm/warp_client.go @@ -8,9 +8,9 @@ import ( "fmt" "github.com/ava-labs/subnet-evm/rpc" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ava-labs/avalanchego/utils/cb58" - "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/subnet-evm/plugin/evm/message" ) @@ -18,7 +18,7 @@ import ( var _ WarpClient = (*warpClient)(nil) type WarpClient interface { - GetSignature(ctx context.Context, signatureRequest message.SignatureRequest) (*[bls.SignatureLen]byte, error) + GetSignature(ctx context.Context, signatureRequest message.SignatureRequest) (*hexutil.Bytes, error) } // warpClient implementation for interacting with EVM [chain] @@ -38,13 +38,13 @@ func NewWarpClient(uri, chain string) (WarpClient, error) { } // GetSignature requests the BLS signature associated with a messageID -func (c *warpClient) GetSignature(ctx context.Context, signatureRequest message.SignatureRequest) (*[bls.SignatureLen]byte, error) { +func (c *warpClient) GetSignature(ctx context.Context, signatureRequest message.SignatureRequest) (*hexutil.Bytes, error) { req, err := cb58.Encode(signatureRequest.MessageID[:]) if err != nil { return nil, fmt.Errorf("failed to base58 encode the request. messageID: %s, error: %w", signatureRequest.MessageID, err) } - var res message.SignatureResponse + var res SignatureResponse err = c.client.CallContext(ctx, &res, "warp_getSignature", req) if err != nil { return nil, fmt.Errorf("call to warp_getSignature failed. err: %w", err) From 453e543be65060639a8f26827acb4d1cb2278e5a Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Thu, 9 Feb 2023 09:36:18 -0800 Subject: [PATCH 49/50] nits for get-signature-endpoint (#502) Co-authored-by: Darioush Jalali Co-authored-by: aaronbuchwald Co-authored-by: Ceyhun Onur Co-authored-by: cam-schultz <78878559+cam-schultz@users.noreply.github.com> --- .github/CONTRIBUTING.md | 17 ++++++++++--- .github/pull_request_template.md | 2 ++ .github/workflows/lint-tests-release.yml | 2 +- contract-examples/hardhat.config.ts | 2 +- go.mod | 5 ++-- go.sum | 10 +++++--- plugin/evm/gossiper.go | 4 +-- plugin/evm/{snowman_service.go => service.go} | 2 +- plugin/evm/vm.go | 25 ++++++++----------- plugin/evm/warp/backend.go | 8 +++--- plugin/evm/warp_client.go | 6 ++--- plugin/evm/warp_service.go | 7 ++++-- scripts/generate_precompile.sh | 21 ++++++++++++++++ scripts/versions.sh | 2 +- 14 files changed, 73 insertions(+), 40 deletions(-) rename plugin/evm/{snowman_service.go => service.go} (95%) create mode 100755 scripts/generate_precompile.sh diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 5381269fcb..d0c9fae378 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -14,13 +14,12 @@ well as our review and merge procedures quick and simple. ## Coding guidelines -Please make sure your contributions adhere to our coding guidelines: +Please make sure your contributions adhere to our coding and documentation +guidelines: - Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)). -- Code must be documented adhering to the official Go - [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines. - Pull requests need to be based on and opened against the `master` branch. - Pull reuqests should include a detailed description - Commits are required to be signed. See [here](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits) @@ -28,6 +27,18 @@ Please make sure your contributions adhere to our coding guidelines: - Commit messages should be prefixed with the package(s) they modify. - E.g. "eth, rpc: make trace configs optional" +## Documentation guidelines + +- Code should be well commented, so it is easier to read and maintain. + Any complex sections or invariants should be documented explicitly. +- Code must be documented adhering to the official Go + [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines. +- Changes with user facing impact (e.g., addition or modification of flags and + options) should be accompanied by a link to a pull request to the [avalanche-docs](https://github.com/ava-labs/avalanche-docs) + repository. [example](https://github.com/ava-labs/avalanche-docs/pull/1119/files). +- Changes that modify a package significantly or add new features should + either update the existing or include a new `README.md` file in that package. + ## Can I have feature X Before you submit a feature request, please check and make sure that it isn't diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 8200c0597f..119cac2eb9 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -3,3 +3,5 @@ ## How this works ## How this was tested + +## How is this documented diff --git a/.github/workflows/lint-tests-release.yml b/.github/workflows/lint-tests-release.yml index a478938e62..5862ddfc2f 100644 --- a/.github/workflows/lint-tests-release.yml +++ b/.github/workflows/lint-tests-release.yml @@ -11,7 +11,7 @@ on: jobs: lint_test: name: Lint - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 - run: ./scripts/lint_allowed_geth_imports.sh diff --git a/contract-examples/hardhat.config.ts b/contract-examples/hardhat.config.ts index be74e1ecb4..1e4c995b7d 100644 --- a/contract-examples/hardhat.config.ts +++ b/contract-examples/hardhat.config.ts @@ -4,7 +4,7 @@ import "./tasks.ts" // HardHat users must populate these environment variables in order to connect to their subnet-evm instance // Since the blockchainID is not known in advance, there's no good default to use and we use the C-Chain here. var local_rpc_uri = process.env.RPC_URI || "http://127.0.0.1:9650/ext/bc/C/rpc" -var local_chain_id = process.env.CHAIN_ID || 99999 +var local_chain_id = parseInt(process.env.CHAIN_ID,10) || 99999 export default { solidity: { diff --git a/go.mod b/go.mod index fb7fb410a9..72b82932ec 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/VictoriaMetrics/fastcache v1.10.0 - github.com/ava-labs/avalanchego v1.9.7 + github.com/ava-labs/avalanchego v1.9.8 github.com/cespare/cp v0.1.0 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set v1.8.0 @@ -27,7 +27,7 @@ require ( github.com/onsi/gomega v1.24.2 github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_model v0.3.0 - github.com/rjeczalik/notify v0.9.2 + github.com/rjeczalik/notify v0.9.3 github.com/shirou/gopsutil v3.21.11+incompatible github.com/spf13/cast v1.5.0 github.com/spf13/pflag v1.0.5 @@ -94,6 +94,7 @@ require ( github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.1 // indirect github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 // indirect + github.com/pires/go-proxyproto v0.6.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/common v0.37.0 // indirect diff --git a/go.sum b/go.sum index eac7c26609..0b4e002aee 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,8 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= -github.com/ava-labs/avalanchego v1.9.7 h1:f2vS8jUBZmrqPcfU5NEa7dSHXbKfTB0EyjcCyvqxqPw= -github.com/ava-labs/avalanchego v1.9.7/go.mod h1:ckdSQHeoRN6PmQ3TLgWAe6Kh9tFpU4Lu6MgDW4GrU/Q= +github.com/ava-labs/avalanchego v1.9.8 h1:5SHKqkWpBn9Pqxg2qpzDZ7FQqYFapzaCZwArapBdqAA= +github.com/ava-labs/avalanchego v1.9.8/go.mod h1:t9+R55TgRJxYCekRf/EicIjHBeeEQT04TQxpaF98+yM= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -465,6 +465,8 @@ github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQm github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8= +github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -503,8 +505,8 @@ github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0ua github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic= github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= -github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8= -github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= +github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZeY= +github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= diff --git a/plugin/evm/gossiper.go b/plugin/evm/gossiper.go index 300958b78d..bc19021ebf 100644 --- a/plugin/evm/gossiper.go +++ b/plugin/evm/gossiper.go @@ -62,7 +62,7 @@ type pushGossiper struct { // [recentTxs] prevent us from over-gossiping the // same transaction in a short period of time. - recentTxs *cache.LRU + recentTxs *cache.LRU[common.Hash, interface{}] codec codec.Manager signer types.Signer @@ -86,7 +86,7 @@ func (vm *VM) createGossiper(stats GossipStats) Gossiper { txsToGossip: make(map[common.Hash]*types.Transaction), shutdownChan: vm.shutdownChan, shutdownWg: &vm.shutdownWg, - recentTxs: &cache.LRU{Size: recentCacheSize}, + recentTxs: &cache.LRU[common.Hash, interface{}]{Size: recentCacheSize}, codec: vm.networkCodec, signer: types.LatestSigner(vm.blockChain.Config()), stats: stats, diff --git a/plugin/evm/snowman_service.go b/plugin/evm/service.go similarity index 95% rename from plugin/evm/snowman_service.go rename to plugin/evm/service.go index d4113ce203..54b5021a45 100644 --- a/plugin/evm/snowman_service.go +++ b/plugin/evm/service.go @@ -1,4 +1,4 @@ -// (c) 2019-2023, Ava Labs, Inc. All rights reserved. +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. package evm diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 10f3fc9924..ec7de69e9f 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -8,7 +8,6 @@ import ( "encoding/json" "errors" "fmt" - "math/big" "os" "path/filepath" "strings" @@ -83,10 +82,10 @@ const ( // and fail verification maxFutureBlockTime = 10 * time.Second - decidedCacheSize = 100 - missingCacheSize = 50 - unverifiedCacheSize = 50 - signatureCacheSize = 500 + decidedCacheSize = 100 + missingCacheSize = 50 + unverifiedCacheSize = 50 + warpSignatureCacheSize = 500 // Prefixes for metrics gatherers ethMetricsPrefix = "eth" @@ -182,6 +181,7 @@ type VM struct { acceptedBlockDB database.Database // [warpDB] is used to store warp message signatures + // set to a prefixDB with the prefix [warpPrefix] warpDB database.Database toEngine chan<- commonEng.Message @@ -214,8 +214,9 @@ type VM struct { StateSyncServer StateSyncClient - // AWM backend - backend warp.WarpBackend + // Avalanche Warp Messaging backend + // Used to serve BLS signatures of warp messages over RPC + warpBackend warp.WarpBackend } /* @@ -427,7 +428,7 @@ func (vm *VM) Initialize( vm.client = peer.NewNetworkClient(vm.Network) // initialize warp backend - vm.backend = warp.NewWarpBackend(vm.ctx, vm.warpDB, signatureCacheSize) + vm.warpBackend = warp.NewWarpBackend(vm.ctx, vm.warpDB, warpSignatureCacheSize) if err := vm.initializeChain(lastAcceptedHash, vm.ethConfig); err != nil { return err @@ -810,7 +811,7 @@ func (vm *VM) CreateHandlers(context.Context) (map[string]*commonEng.HTTPHandler } if vm.config.WarpAPIEnabled { - if err := handler.RegisterName("warp", &WarpAPI{vm}); err != nil { + if err := handler.RegisterName("warp", &WarpAPI{vm.warpBackend}); err != nil { return nil, err } enabledAPIs = append(enabledAPIs, "warp") @@ -867,12 +868,6 @@ func (vm *VM) GetCurrentNonce(address common.Address) (uint64, error) { return state.GetNonce(address), nil } -// currentRules returns the chain rules for the current block. -func (vm *VM) currentRules() params.Rules { - header := vm.eth.APIBackend.CurrentHeader() - return vm.chainConfig.AvalancheRules(header.Number, big.NewInt(int64(header.Time))) -} - func (vm *VM) startContinuousProfiler() { // If the profiler directory is empty, return immediately // without creating or starting a continuous profiler. diff --git a/plugin/evm/warp/backend.go b/plugin/evm/warp/backend.go index 7aade1514d..9817ff9802 100644 --- a/plugin/evm/warp/backend.go +++ b/plugin/evm/warp/backend.go @@ -36,7 +36,7 @@ type WarpBackend interface { type warpBackend struct { db database.Database snowCtx *snow.Context - signatureCache *cache.LRU + signatureCache *cache.LRU[ids.ID, [bls.SignatureLen]byte] } // NewWarpBackend creates a new WarpBackend, and initializes the signature cache and message tracking database. @@ -44,7 +44,7 @@ func NewWarpBackend(snowCtx *snow.Context, db database.Database, signatureCacheS return &warpBackend{ db: db, snowCtx: snowCtx, - signatureCache: &cache.LRU{Size: signatureCacheSize}, + signatureCache: &cache.LRU[ids.ID, [bls.SignatureLen]byte]{Size: signatureCacheSize}, } } @@ -71,7 +71,7 @@ func (w *warpBackend) AddMessage(ctx context.Context, unsignedMessage *teleporte func (w *warpBackend) GetSignature(ctx context.Context, messageID ids.ID) ([bls.SignatureLen]byte, error) { if sig, ok := w.signatureCache.Get(messageID); ok { - return sig.([bls.SignatureLen]byte), nil + return sig, nil } unsignedMessageBytes, err := w.db.Get(messageID[:]) @@ -91,6 +91,6 @@ func (w *warpBackend) GetSignature(ctx context.Context, messageID ids.ID) ([bls. } copy(signature[:], sig) - w.signatureCache.Put(messageID[:], signature) + w.signatureCache.Put(messageID, signature) return signature, nil } diff --git a/plugin/evm/warp_client.go b/plugin/evm/warp_client.go index 874ce5073d..42fd1c262e 100644 --- a/plugin/evm/warp_client.go +++ b/plugin/evm/warp_client.go @@ -7,14 +7,12 @@ import ( "context" "fmt" - "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ava-labs/avalanchego/utils/cb58" "github.com/ava-labs/subnet-evm/plugin/evm/message" + "github.com/ava-labs/subnet-evm/rpc" + "github.com/ethereum/go-ethereum/common/hexutil" ) -// Interface compliance var _ WarpClient = (*warpClient)(nil) type WarpClient interface { diff --git a/plugin/evm/warp_service.go b/plugin/evm/warp_service.go index 36264008d6..3ee4823cea 100644 --- a/plugin/evm/warp_service.go +++ b/plugin/evm/warp_service.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/subnet-evm/plugin/evm/warp" "github.com/ethereum/go-ethereum/common/hexutil" ) @@ -16,11 +17,13 @@ type SignatureResponse struct { } // WarpAPI introduces snowman specific functionality to the evm -type WarpAPI struct{ vm *VM } +type WarpAPI struct { + backend warp.WarpBackend +} // GetSignature returns the BLS signature associated with a messageID. In the raw request, [messageID] should be cb58 encoded func (api *WarpAPI) GetSignature(ctx context.Context, messageID ids.ID) (*SignatureResponse, error) { - signature, err := api.vm.backend.GetSignature(ctx, messageID) + signature, err := api.backend.GetSignature(ctx, messageID) if err != nil { return nil, fmt.Errorf("failed to get signature for with error %w", err) } diff --git a/scripts/generate_precompile.sh b/scripts/generate_precompile.sh new file mode 100755 index 0000000000..8876880659 --- /dev/null +++ b/scripts/generate_precompile.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -e + +# This script generates a Stateful Precompile stub based off of a Solidity ABI file. +# It first sets the necessary CGO_FLAGs for the BLST library used in AvalancheGo and +# then runs PrecompileGen. +if ! [[ "$0" =~ scripts/generate_precompile.sh ]]; then + echo "must be run from repository root, but got $0" + exit 255 +fi + +# Load the versions +SUBNET_EVM_PATH=$( + cd "$(dirname "${BASH_SOURCE[0]}")" + cd .. && pwd +) + +# Load the constants +source "$SUBNET_EVM_PATH"/scripts/constants.sh + +go run ./cmd/precompilegen/main.go $@ diff --git a/scripts/versions.sh b/scripts/versions.sh index 4572877092..708a8c549a 100644 --- a/scripts/versions.sh +++ b/scripts/versions.sh @@ -3,7 +3,7 @@ # Set up the versions to be used - populate ENV variables only if they are not already populated SUBNET_EVM_VERSION=${SUBNET_EVM_VERSION:-'v0.4.9'} # Don't export them as they're used in the context of other calls -AVALANCHEGO_VERSION=${AVALANCHE_VERSION:-'v1.9.7'} +AVALANCHEGO_VERSION=${AVALANCHE_VERSION:-'v1.9.8'} GINKGO_VERSION=${GINKGO_VERSION:-'v2.2.0'} # This won't be used, but it's here to make code syncs easier From b0efb9dace2238b423f2907f0d6d9ff7b441896a Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Thu, 9 Feb 2023 21:07:02 +0000 Subject: [PATCH 50/50] resolve merge conflict --- handlers/signature_request.go | 75 ---------------------- handlers/signature_request_test.go | 99 ------------------------------ 2 files changed, 174 deletions(-) delete mode 100644 handlers/signature_request.go delete mode 100644 handlers/signature_request_test.go diff --git a/handlers/signature_request.go b/handlers/signature_request.go deleted file mode 100644 index d45dcd47d3..0000000000 --- a/handlers/signature_request.go +++ /dev/null @@ -1,75 +0,0 @@ -// (c) 2023, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package handlers - -import ( - "context" - "time" - - "github.com/ava-labs/avalanchego/codec" - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/subnet-evm/handlers/warp/stats" - "github.com/ava-labs/subnet-evm/plugin/evm/message" - "github.com/ava-labs/subnet-evm/plugin/evm/warp" - "github.com/ethereum/go-ethereum/log" -) - -// SignatureRequestHandler is a peer.RequestHandler for message.SignatureRequest -// serving requested BLS signature data -type SignatureRequestHandler interface { - OnSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) -} - -// signatureRequestHandler implements the SignatureRequestHandler interface -type signatureRequestHandler struct { - backend warp.WarpBackend - codec codec.Manager - stats stats.SignatureRequestHandlerStats -} - -func NewSignatureRequestHandler(backend warp.WarpBackend, codec codec.Manager, stats stats.SignatureRequestHandlerStats) SignatureRequestHandler { - return &signatureRequestHandler{ - backend: backend, - codec: codec, - stats: stats, - } -} - -// OnSignatureRequest handles message.SignatureRequest, and retrieves a warp signature for the requested message ID. -// Never returns an error -// Expects returned errors to be treated as FATAL -// Returns empty response if signature is not found -// Assumes ctx is active -func (s *signatureRequestHandler) OnSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) { - startTime := time.Now() - s.stats.IncSignatureRequest() - - // Always report signature request time - defer func() { - s.stats.UpdateSignatureRequestTime(time.Since(startTime)) - }() - - signature, err := s.backend.GetSignature(ctx, signatureRequest.MessageID) - if err != nil { - log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID) - s.stats.IncSignatureMiss() - return nil, nil - } - - s.stats.IncSignatureHit() - response := message.SignatureResponse{Signature: signature} - responseBytes, err := s.codec.Marshal(message.Version, response) - if err != nil { - log.Warn("could not marshal SignatureResponse, dropping request", "nodeID", nodeID, "requestID", requestID, "err", err) - return nil, nil - } - - return responseBytes, nil -} - -type NoopSignatureRequestHandler struct{} - -func (s *NoopSignatureRequestHandler) OnSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) { - return nil, nil -} diff --git a/handlers/signature_request_test.go b/handlers/signature_request_test.go deleted file mode 100644 index 0a2d5c75ca..0000000000 --- a/handlers/signature_request_test.go +++ /dev/null @@ -1,99 +0,0 @@ -// (c) 2023, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package handlers - -import ( - "context" - "testing" - "time" - - "github.com/ava-labs/avalanchego/database/memdb" - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/snow" - "github.com/ava-labs/avalanchego/utils/crypto/bls" - "github.com/ava-labs/avalanchego/utils/hashing" - "github.com/ava-labs/avalanchego/vms/platformvm/teleporter" - "github.com/ava-labs/subnet-evm/handlers/stats" - "github.com/ava-labs/subnet-evm/plugin/evm/message" - "github.com/ava-labs/subnet-evm/plugin/evm/warp" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestSignatureHandler(t *testing.T) { - database := memdb.New() - snowCtx := snow.DefaultContextTest() - blsSecretKey, err := bls.NewSecretKey() - require.NoError(t, err) - - snowCtx.TeleporterSigner = teleporter.NewSigner(blsSecretKey, snowCtx.ChainID) - warpBackend := warp.NewWarpBackend(snowCtx, database, 100) - - msg, err := teleporter.NewUnsignedMessage(snowCtx.ChainID, snowCtx.CChainID, []byte("test")) - require.NoError(t, err) - - messageID := hashing.ComputeHash256Array(msg.Bytes()) - require.NoError(t, warpBackend.AddMessage(context.Background(), msg)) - signature, err := warpBackend.GetSignature(context.Background(), messageID) - require.NoError(t, err) - unknownMessageID := ids.GenerateTestID() - - mockHandlerStats := &stats.MockHandlerStats{} - signatureRequestHandler := NewSignatureRequestHandler(warpBackend, message.Codec, mockHandlerStats) - - tests := map[string]struct { - setup func() (request message.SignatureRequest, expectedResponse []byte) - verifyStats func(t *testing.T, stats *stats.MockHandlerStats) - }{ - "normal": { - setup: func() (request message.SignatureRequest, expectedResponse []byte) { - return message.SignatureRequest{ - MessageID: messageID, - }, signature[:] - }, - verifyStats: func(t *testing.T, stats *stats.MockHandlerStats) { - assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestCount) - assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestHit) - assert.Greater(t, mockHandlerStats.SignatureRequestDuration, time.Duration(0)) - }, - }, - "unknown": { - setup: func() (request message.SignatureRequest, expectedResponse []byte) { - return message.SignatureRequest{ - MessageID: unknownMessageID, - }, nil - }, - verifyStats: func(t *testing.T, stats *stats.MockHandlerStats) { - assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestCount) - assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestMiss) - assert.Greater(t, mockHandlerStats.SignatureRequestDuration, time.Duration(0)) - }, - }, - } - - for name, test := range tests { - // Reset stats before each test - mockHandlerStats.Reset() - - t.Run(name, func(t *testing.T) { - request, expectedResponse := test.setup() - responseBytes, err := signatureRequestHandler.OnSignatureRequest(context.Background(), ids.GenerateTestNodeID(), 1, request) - assert.NoError(t, err) - - // If the expected response is empty, assert that the handler returns an empty response and return early. - if len(expectedResponse) == 0 { - assert.Len(t, responseBytes, 0, "expected response to be empty") - return - } - var response message.SignatureResponse - _, err = message.Codec.Unmarshal(responseBytes, &response) - require.NoError(t, err, "error unmarshalling SignatureResponse") - - var expectedSignature [bls.SignatureLen]byte - copy(expectedSignature[:], expectedResponse) - assert.Equal(t, expectedSignature, response.Signature) - test.verifyStats(t, mockHandlerStats) - }) - } -}