From e6219a2c365b5d4918e4f00346d6e209837414b8 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Thu, 19 Jan 2023 15:02:30 -0800 Subject: [PATCH 01/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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/46] 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 76febbaab07ab5d246bc7034604603449962e005 Mon Sep 17 00:00:00 2001 From: minghinmatthewlam Date: Thu, 2 Feb 2023 12:41:09 -0800 Subject: [PATCH 34/46] 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 35/46] 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 36/46] 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 37/46] 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 38/46] 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 62f250f17ab1dd6e68a119fe634232d491cdedc0 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Mon, 6 Feb 2023 15:55:02 -0800 Subject: [PATCH 39/46] signature request test for noop signature request handler --- handlers/signature_request.go | 2 +- plugin/evm/vm_test.go | 80 ++++++++++++++++++++++++++--------- 2 files changed, 61 insertions(+), 21 deletions(-) diff --git a/handlers/signature_request.go b/handlers/signature_request.go index c451d1d154..097fad41a5 100644 --- a/handlers/signature_request.go +++ b/handlers/signature_request.go @@ -59,7 +59,7 @@ func (s *signatureRequestHandler) OnSignatureRequest(ctx context.Context, nodeID s.stats.IncSignatureHit() response := message.SignatureResponse{Signature: signature} - responseBytes, err := s.codec.Marshal(message.Version, response) + 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 diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 65f98e92db..b07827f845 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -564,11 +564,14 @@ func TestBuildEthTxBlock(t *testing.T) { // then calling SetPreference on block B (when it becomes preferred) // and the head of a longer chain (block D) does not corrupt the // canonical chain. -// A +// +// A +// // / \ // B C -// | -// D +// +// | +// D func TestSetPreferenceRace(t *testing.T) { // Create two VMs which will agree on block A and then // build the two distinct preferred chains above @@ -813,9 +816,11 @@ func TestSetPreferenceRace(t *testing.T) { // will not attempt to orphan either when verifying blocks C and D // from another VM (which have a common ancestor under the finalized // frontier). -// A -// / \ -// B C +// +// A +// / \ +// +// # B C // // verifies block B and C, then Accepts block B. Then we test to ensure // that the VM defends against any attempt to set the preference or to @@ -995,8 +1000,10 @@ func TestReorgProtection(t *testing.T) { // Regression test to ensure that a VM that accepts block C while preferring // block B will trigger a reorg. -// A -// / \ +// +// A +// / \ +// // B C func TestNonCanonicalAccept(t *testing.T) { issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") @@ -1163,11 +1170,14 @@ func TestNonCanonicalAccept(t *testing.T) { // Regression test to ensure that a VM that verifies block B, C, then // D (preferring block B) does not trigger a reorg through the re-verification // of block C or D. -// A -// / \ +// +// A +// / \ +// // B C -// | -// D +// +// | +// D func TestStickyPreference(t *testing.T) { issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") issuer2, vm2, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") @@ -1432,11 +1442,14 @@ func TestStickyPreference(t *testing.T) { // Regression test to ensure that a VM that prefers block B is able to parse // block C but unable to parse block D because it names B as an uncle, which // are not supported. -// A -// / \ +// +// A +// / \ +// // B C -// | -// D +// +// | +// D func TestUncleBlock(t *testing.T) { issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") issuer2, vm2, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") @@ -1678,11 +1691,14 @@ func TestEmptyBlock(t *testing.T) { // Regression test to ensure that a VM that verifies block B, C, then // D (preferring block B) reorgs when C and then D are accepted. -// A -// / \ +// +// A +// / \ +// // B C -// | -// D +// +// | +// D func TestAcceptReorg(t *testing.T) { issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") issuer2, vm2, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") @@ -3157,3 +3173,27 @@ func TestCrossChainMessagestoVM(t *testing.T) { require.NoError(err) require.True(calledSendCrossChainAppResponseFn, "sendCrossChainAppResponseFn was not called") } + +func TestSignatureRequestsToVM(t *testing.T) { + codec := message.Codec + _, vm, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") + + defer func() { + err := vm.Shutdown(context.Background()) + require.NoError(t, err) + }() + + // Generate a SignatureRequest for an unknown message + var signatureRequest message.Request = message.SignatureRequest{ + MessageID: ids.GenerateTestID(), + } + + requestBytes, err := codec.Marshal(message.Version, &signatureRequest) + require.NoError(t, err) + + // Currently with warp not being initialized we just need to make sure the NoopSignatureRequestHandler does not + // panic/crash when sent a SignatureRequest. + // TODO: We will need to update the test when warp is initialized to check for expected response. + err = vm.Network.AppRequest(context.Background(), ids.GenerateTestNodeID(), 1, time.Now().Add(60*time.Second), requestBytes) + require.NoError(t, err) +} From 3679478bdd5ea3faa3daf083fcea1de32219305a Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Mon, 6 Feb 2023 16:22:22 -0800 Subject: [PATCH 40/46] remove tree changes --- plugin/evm/vm_test.go | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index b07827f845..80a7c81bb7 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -564,14 +564,11 @@ func TestBuildEthTxBlock(t *testing.T) { // then calling SetPreference on block B (when it becomes preferred) // and the head of a longer chain (block D) does not corrupt the // canonical chain. -// -// A -// +// A // / \ // B C -// -// | -// D +// | +// D func TestSetPreferenceRace(t *testing.T) { // Create two VMs which will agree on block A and then // build the two distinct preferred chains above @@ -820,8 +817,7 @@ func TestSetPreferenceRace(t *testing.T) { // A // / \ // -// # B C -// +// B C // verifies block B and C, then Accepts block B. Then we test to ensure // that the VM defends against any attempt to set the preference or to // accept block C, which should be an orphaned block at this point and @@ -1000,10 +996,8 @@ func TestReorgProtection(t *testing.T) { // Regression test to ensure that a VM that accepts block C while preferring // block B will trigger a reorg. -// // A // / \ -// // B C func TestNonCanonicalAccept(t *testing.T) { issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") @@ -1170,14 +1164,11 @@ func TestNonCanonicalAccept(t *testing.T) { // Regression test to ensure that a VM that verifies block B, C, then // D (preferring block B) does not trigger a reorg through the re-verification // of block C or D. -// // A // / \ -// // B C -// -// | -// D +// | +// D func TestStickyPreference(t *testing.T) { issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") issuer2, vm2, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") @@ -1442,14 +1433,11 @@ func TestStickyPreference(t *testing.T) { // Regression test to ensure that a VM that prefers block B is able to parse // block C but unable to parse block D because it names B as an uncle, which // are not supported. -// // A // / \ -// // B C -// -// | -// D +// | +// D func TestUncleBlock(t *testing.T) { issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") issuer2, vm2, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") @@ -1691,14 +1679,11 @@ func TestEmptyBlock(t *testing.T) { // Regression test to ensure that a VM that verifies block B, C, then // D (preferring block B) reorgs when C and then D are accepted. -// // A // / \ -// // B C -// -// | -// D +// | +// D func TestAcceptReorg(t *testing.T) { issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") issuer2, vm2, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") From 5c08d07620558b6d33bf4c2343dcfd330c278128 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Mon, 6 Feb 2023 16:33:25 -0800 Subject: [PATCH 41/46] fix pr comments --- plugin/evm/vm_test.go | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 80a7c81bb7..2725596b48 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -813,11 +813,10 @@ func TestSetPreferenceRace(t *testing.T) { // will not attempt to orphan either when verifying blocks C and D // from another VM (which have a common ancestor under the finalized // frontier). -// -// A -// / \ -// +// A +// / \ // B C +// // verifies block B and C, then Accepts block B. Then we test to ensure // that the VM defends against any attempt to set the preference or to // accept block C, which should be an orphaned block at this point and @@ -996,8 +995,8 @@ func TestReorgProtection(t *testing.T) { // Regression test to ensure that a VM that accepts block C while preferring // block B will trigger a reorg. -// A -// / \ +// A +// / \ // B C func TestNonCanonicalAccept(t *testing.T) { issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") @@ -1164,11 +1163,11 @@ func TestNonCanonicalAccept(t *testing.T) { // Regression test to ensure that a VM that verifies block B, C, then // D (preferring block B) does not trigger a reorg through the re-verification // of block C or D. -// A -// / \ +// A +// / \ // B C -// | -// D +// | +// D func TestStickyPreference(t *testing.T) { issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") issuer2, vm2, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") @@ -1433,11 +1432,11 @@ func TestStickyPreference(t *testing.T) { // Regression test to ensure that a VM that prefers block B is able to parse // block C but unable to parse block D because it names B as an uncle, which // are not supported. -// A -// / \ +// A +// / \ // B C -// | -// D +// | +// D func TestUncleBlock(t *testing.T) { issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") issuer2, vm2, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") @@ -1679,11 +1678,11 @@ func TestEmptyBlock(t *testing.T) { // Regression test to ensure that a VM that verifies block B, C, then // D (preferring block B) reorgs when C and then D are accepted. -// A -// / \ +// A +// / \ // B C -// | -// D +// | +// D func TestAcceptReorg(t *testing.T) { issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") issuer2, vm2, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") @@ -3160,7 +3159,6 @@ func TestCrossChainMessagestoVM(t *testing.T) { } func TestSignatureRequestsToVM(t *testing.T) { - codec := message.Codec _, vm, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "") defer func() { @@ -3173,7 +3171,7 @@ func TestSignatureRequestsToVM(t *testing.T) { MessageID: ids.GenerateTestID(), } - requestBytes, err := codec.Marshal(message.Version, &signatureRequest) + requestBytes, err := message.Codec.Marshal(message.Version, &signatureRequest) require.NoError(t, err) // Currently with warp not being initialized we just need to make sure the NoopSignatureRequestHandler does not From 56dc93ba4a283d8e3d27743768f7e7e54dc4317b Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Mon, 6 Feb 2023 16:54:01 -0800 Subject: [PATCH 42/46] Signature handler refactor (#495) * Refactor signature handler and stats * Remove unnecessary lock --- handlers/handler.go | 5 +- handlers/stats/mock_stats.go | 152 +--------- handlers/stats/stats.go | 269 +----------------- handlers/{ => warp}/signature_request.go | 4 +- handlers/{ => warp}/signature_request_test.go | 2 +- handlers/warp/stats/stats.go | 95 +++++++ plugin/evm/warp/backend.go | 8 +- 7 files changed, 119 insertions(+), 416 deletions(-) rename handlers/{ => warp}/signature_request.go (97%) rename handlers/{ => warp}/signature_request_test.go (99%) create mode 100644 handlers/warp/stats/stats.go diff --git a/handlers/handler.go b/handlers/handler.go index 79eff82d70..0ab0a626fb 100644 --- a/handlers/handler.go +++ b/handlers/handler.go @@ -9,6 +9,7 @@ import ( "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/subnet-evm/handlers/stats" + warpHandlers "github.com/ava-labs/subnet-evm/handlers/warp" "github.com/ava-labs/subnet-evm/metrics" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/sync/handlers" @@ -22,7 +23,7 @@ type networkHandler struct { stateTrieLeafsRequestHandler *syncHandlers.LeafsRequestHandler blockRequestHandler *syncHandlers.BlockRequestHandler codeRequestHandler *syncHandlers.CodeRequestHandler - signatureRequestHandler SignatureRequestHandler + signatureRequestHandler warpHandlers.SignatureRequestHandler } // NewNetworkHandler constructs the handler for serving network requests. @@ -39,7 +40,7 @@ func NewNetworkHandler( codeRequestHandler: syncHandlers.NewCodeRequestHandler(evmTrieDB.DiskDB(), networkCodec, handlerStats), // TODO: initialize actual signature request handler when warp is ready - signatureRequestHandler: &NoopSignatureRequestHandler{}, + signatureRequestHandler: &warpHandlers.NoopSignatureRequestHandler{}, } } diff --git a/handlers/stats/mock_stats.go b/handlers/stats/mock_stats.go index ab9b4e340d..45ffb7aaa2 100644 --- a/handlers/stats/mock_stats.go +++ b/handlers/stats/mock_stats.go @@ -4,9 +4,7 @@ package stats import ( - "sync" - "time" - + warpStats "github.com/ava-labs/subnet-evm/handlers/warp/stats" syncStats "github.com/ava-labs/subnet-evm/sync/handlers/stats" ) @@ -14,151 +12,11 @@ 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 + syncStats.MockHandlerStats + warpStats.MockSignatureRequestHandlerStats } 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 + m.MockHandlerStats.Reset() + m.MockSignatureRequestHandlerStats.Reset() } diff --git a/handlers/stats/stats.go b/handlers/stats/stats.go index 946027a910..357eb18f0b 100644 --- a/handlers/stats/stats.go +++ b/handlers/stats/stats.go @@ -4,284 +4,35 @@ package stats import ( - "time" - - "github.com/ava-labs/subnet-evm/metrics" + warpStats "github.com/ava-labs/subnet-evm/handlers/warp/stats" syncStats "github.com/ava-labs/subnet-evm/sync/handlers/stats" ) var ( _ HandlerStats = &handlerStats{} - _ HandlerStats = &noopHandlerStats{} + _ HandlerStats = &MockHandlerStats{} ) // HandlerStats reports prometheus metrics for the network handlers type HandlerStats interface { - SignatureRequestHandlerStats + warpStats.SignatureRequestHandlerStats syncStats.HandlerStats } -type SignatureRequestHandlerStats interface { - IncSignatureRequest() - IncSignatureHit() - IncSignatureMiss() - UpdateSignatureRequestTime(duration time.Duration) -} - type handlerStats struct { - // State sync metrics - 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() -} + // State sync handler metrics + syncStats.HandlerStats -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) + // Warp handler metrics + warpStats.SignatureRequestHandlerStats } func NewHandlerStats(enabled bool) HandlerStats { if !enabled { - return NewNoopHandlerStats() + return &MockHandlerStats{} } return &handlerStats{ - // initialize state sync handler stats - syncHandlerStats: syncStats.NewHandlerStats(enabled), - - // 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), + HandlerStats: syncStats.NewHandlerStats(enabled), + SignatureRequestHandlerStats: warpStats.NewStats(enabled), } } - -// 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/handlers/signature_request.go b/handlers/warp/signature_request.go similarity index 97% rename from handlers/signature_request.go rename to handlers/warp/signature_request.go index 097fad41a5..13b6c7e66b 100644 --- a/handlers/signature_request.go +++ b/handlers/warp/signature_request.go @@ -1,7 +1,7 @@ // (c) 2023, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package handlers +package warp import ( "context" @@ -9,7 +9,7 @@ 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/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" diff --git a/handlers/signature_request_test.go b/handlers/warp/signature_request_test.go similarity index 99% rename from handlers/signature_request_test.go rename to handlers/warp/signature_request_test.go index 0a2d5c75ca..d5e3103063 100644 --- a/handlers/signature_request_test.go +++ b/handlers/warp/signature_request_test.go @@ -1,7 +1,7 @@ // (c) 2023, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package handlers +package warp import ( "context" diff --git a/handlers/warp/stats/stats.go b/handlers/warp/stats/stats.go new file mode 100644 index 0000000000..2cc593667e --- /dev/null +++ b/handlers/warp/stats/stats.go @@ -0,0 +1,95 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package stats + +import ( + "sync" + "time" + + "github.com/ava-labs/subnet-evm/metrics" +) + +var ( + _ SignatureRequestHandlerStats = (*handlerStats)(nil) + _ SignatureRequestHandlerStats = (*MockSignatureRequestHandlerStats)(nil) +) + +type SignatureRequestHandlerStats interface { + IncSignatureRequest() + IncSignatureHit() + IncSignatureMiss() + UpdateSignatureRequestTime(duration time.Duration) +} + +type handlerStats struct { + // SignatureRequestHandler metrics + signatureRequest metrics.Counter + signatureHit metrics.Counter + signatureMiss metrics.Counter + signatureProcessingTime metrics.Timer +} + +func NewStats(enabled bool) SignatureRequestHandlerStats { + if !enabled { + return &MockSignatureRequestHandlerStats{} + } + + return &handlerStats{ + 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), + } +} + +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) +} + +// MockSignatureRequestHandlerStats is mock for capturing and asserting on handler metrics in test +type MockSignatureRequestHandlerStats struct { + lock sync.Mutex + + SignatureRequestCount, + SignatureRequestHit, + SignatureRequestMiss uint32 + SignatureRequestDuration time.Duration +} + +func (m *MockSignatureRequestHandlerStats) Reset() { + m.lock.Lock() + defer m.lock.Unlock() + + m.SignatureRequestCount = 0 + m.SignatureRequestHit = 0 + m.SignatureRequestMiss = 0 + m.SignatureRequestDuration = 0 +} + +func (m *MockSignatureRequestHandlerStats) IncSignatureRequest() { + m.lock.Lock() + defer m.lock.Unlock() + m.SignatureRequestCount++ +} + +func (m *MockSignatureRequestHandlerStats) IncSignatureHit() { + m.lock.Lock() + defer m.lock.Unlock() + m.SignatureRequestHit++ +} + +func (m *MockSignatureRequestHandlerStats) IncSignatureMiss() { + m.lock.Lock() + defer m.lock.Unlock() + m.SignatureRequestMiss++ +} + +func (m *MockSignatureRequestHandlerStats) UpdateSignatureRequestTime(duration time.Duration) { + m.lock.Lock() + defer m.lock.Unlock() + m.SignatureRequestDuration += duration +} diff --git a/plugin/evm/warp/backend.go b/plugin/evm/warp/backend.go index 7aade1514d..004745fdaa 100644 --- a/plugin/evm/warp/backend.go +++ b/plugin/evm/warp/backend.go @@ -18,8 +18,6 @@ import ( var ( _ WarpBackend = &warpBackend{} - - emptySignature = [bls.SignatureLen]byte{} ) // WarpBackend tracks signature eligible warp messages and provides an interface to fetch them. @@ -76,18 +74,18 @@ func (w *warpBackend) GetSignature(ctx context.Context, messageID ids.ID) ([bls. unsignedMessageBytes, err := w.db.Get(messageID[:]) if err != nil { - return emptySignature, fmt.Errorf("failed to get warp message %s from db: %w", messageID.String(), err) + return [bls.SignatureLen]byte{}, fmt.Errorf("failed to get warp message %s from db: %w", messageID.String(), err) } unsignedMessage, err := teleporter.ParseUnsignedMessage(unsignedMessageBytes) if err != nil { - return emptySignature, fmt.Errorf("failed to parse unsigned message %s: %w", messageID.String(), err) + return [bls.SignatureLen]byte{}, fmt.Errorf("failed to parse unsigned message %s: %w", messageID.String(), err) } var signature [bls.SignatureLen]byte sig, err := w.snowCtx.TeleporterSigner.Sign(unsignedMessage) if err != nil { - return emptySignature, fmt.Errorf("failed to sign warp message: %w", err) + return [bls.SignatureLen]byte{}, fmt.Errorf("failed to sign warp message: %w", err) } copy(signature[:], sig) From 1f99cb1397d9be970f95b5352320eed38de8e94b Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Wed, 8 Feb 2023 12:02:19 -0800 Subject: [PATCH 43/46] pr fixes --- handlers/warp/signature_request_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/handlers/warp/signature_request_test.go b/handlers/warp/signature_request_test.go index d5e3103063..d69567c028 100644 --- a/handlers/warp/signature_request_test.go +++ b/handlers/warp/signature_request_test.go @@ -55,6 +55,7 @@ func TestSignatureHandler(t *testing.T) { verifyStats: func(t *testing.T, stats *stats.MockHandlerStats) { assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestCount) assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestHit) + assert.EqualValues(t, 0, mockHandlerStats.SignatureRequestMiss) assert.Greater(t, mockHandlerStats.SignatureRequestDuration, time.Duration(0)) }, }, @@ -67,6 +68,7 @@ func TestSignatureHandler(t *testing.T) { verifyStats: func(t *testing.T, stats *stats.MockHandlerStats) { assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestCount) assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestMiss) + assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestHit) assert.Greater(t, mockHandlerStats.SignatureRequestDuration, time.Duration(0)) }, }, From 943da39b28b71cc01ed534cb37c7aab193bdfc16 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Wed, 8 Feb 2023 12:09:31 -0800 Subject: [PATCH 44/46] resolve conflicts merge master --- plugin/evm/warp/backend.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plugin/evm/warp/backend.go b/plugin/evm/warp/backend.go index eee33a5d3a..d24ed09a39 100644 --- a/plugin/evm/warp/backend.go +++ b/plugin/evm/warp/backend.go @@ -34,7 +34,7 @@ type WarpBackend interface { type warpBackend struct { db database.Database snowCtx *snow.Context - signatureCache *cache.LRU[ids.ID, []byte] + signatureCache *cache.LRU[ids.ID, [bls.SignatureLen]byte] } // NewWarpBackend creates a new WarpBackend, and initializes the signature cache and message tracking database. @@ -63,7 +63,7 @@ func (w *warpBackend) AddMessage(ctx context.Context, unsignedMessage *teleporte } copy(signature[:], sig) - w.signatureCache.Put(ids.ID(messageID), signature) + w.signatureCache.Put(messageID, signature) return nil } @@ -88,8 +88,7 @@ func (w *warpBackend) GetSignature(ctx context.Context, messageID ids.ID) ([bls. return [bls.SignatureLen]byte{}, fmt.Errorf("failed to sign warp message: %w", err) } - w.signatureCache.Put(messageID, signature) copy(signature[:], sig) - w.signatureCache.Put(messageID[:], signature) + w.signatureCache.Put(messageID, signature) return signature, nil } From 36eee412dcad1f929362d38cdaf27d2634e884c0 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Wed, 8 Feb 2023 12:39:54 -0800 Subject: [PATCH 45/46] add verify stats for nil count --- handlers/warp/signature_request_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/handlers/warp/signature_request_test.go b/handlers/warp/signature_request_test.go index d69567c028..fa3e13aaee 100644 --- a/handlers/warp/signature_request_test.go +++ b/handlers/warp/signature_request_test.go @@ -68,7 +68,7 @@ func TestSignatureHandler(t *testing.T) { verifyStats: func(t *testing.T, stats *stats.MockHandlerStats) { assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestCount) assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestMiss) - assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestHit) + assert.EqualValues(t, 0, mockHandlerStats.SignatureRequestHit) assert.Greater(t, mockHandlerStats.SignatureRequestDuration, time.Duration(0)) }, }, @@ -85,6 +85,7 @@ func TestSignatureHandler(t *testing.T) { // If the expected response is empty, assert that the handler returns an empty response and return early. if len(expectedResponse) == 0 { + test.verifyStats(t, mockHandlerStats) assert.Len(t, responseBytes, 0, "expected response to be empty") return } From 38a64a604fc70cc33aaf1e802b8311d4ad046669 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Wed, 8 Feb 2023 16:53:56 -0800 Subject: [PATCH 46/46] Signature handler nits (#501) --- handlers/warp/signature_request_test.go | 25 +++++++++++-------------- plugin/evm/warp/backend.go | 4 +--- plugin/evm/warp/backend_test.go | 8 ++------ 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/handlers/warp/signature_request_test.go b/handlers/warp/signature_request_test.go index fa3e13aaee..e2b435c509 100644 --- a/handlers/warp/signature_request_test.go +++ b/handlers/warp/signature_request_test.go @@ -17,7 +17,6 @@ import ( "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" ) @@ -53,10 +52,10 @@ func TestSignatureHandler(t *testing.T) { }, signature[:] }, verifyStats: func(t *testing.T, stats *stats.MockHandlerStats) { - assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestCount) - assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestHit) - assert.EqualValues(t, 0, mockHandlerStats.SignatureRequestMiss) - assert.Greater(t, mockHandlerStats.SignatureRequestDuration, time.Duration(0)) + require.EqualValues(t, 1, mockHandlerStats.SignatureRequestCount) + require.EqualValues(t, 1, mockHandlerStats.SignatureRequestHit) + require.EqualValues(t, 0, mockHandlerStats.SignatureRequestMiss) + require.Greater(t, mockHandlerStats.SignatureRequestDuration, time.Duration(0)) }, }, "unknown": { @@ -66,10 +65,10 @@ func TestSignatureHandler(t *testing.T) { }, nil }, verifyStats: func(t *testing.T, stats *stats.MockHandlerStats) { - assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestCount) - assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestMiss) - assert.EqualValues(t, 0, mockHandlerStats.SignatureRequestHit) - assert.Greater(t, mockHandlerStats.SignatureRequestDuration, time.Duration(0)) + require.EqualValues(t, 1, mockHandlerStats.SignatureRequestCount) + require.EqualValues(t, 1, mockHandlerStats.SignatureRequestMiss) + require.EqualValues(t, 0, mockHandlerStats.SignatureRequestHit) + require.Greater(t, mockHandlerStats.SignatureRequestDuration, time.Duration(0)) }, }, } @@ -81,21 +80,19 @@ func TestSignatureHandler(t *testing.T) { 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) + require.NoError(t, err) // If the expected response is empty, assert that the handler returns an empty response and return early. if len(expectedResponse) == 0 { test.verifyStats(t, mockHandlerStats) - assert.Len(t, responseBytes, 0, "expected response to be empty") + require.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) + require.Equal(t, expectedResponse, response.Signature[:]) test.verifyStats(t, mockHandlerStats) }) } diff --git a/plugin/evm/warp/backend.go b/plugin/evm/warp/backend.go index d24ed09a39..8cfac0b54e 100644 --- a/plugin/evm/warp/backend.go +++ b/plugin/evm/warp/backend.go @@ -16,9 +16,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/teleporter" ) -var ( - _ WarpBackend = &warpBackend{} -) +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. diff --git a/plugin/evm/warp/backend_test.go b/plugin/evm/warp/backend_test.go index 557af26a60..c4449245f5 100644 --- a/plugin/evm/warp/backend_test.go +++ b/plugin/evm/warp/backend_test.go @@ -42,11 +42,9 @@ 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) - copy(expectedSignature[:], expectedSig) - require.Equal(t, expectedSignature, signature) + require.Equal(t, expectedSig, signature[:]) } func TestAddAndGetUnknownMessage(t *testing.T) { @@ -84,9 +82,7 @@ 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) - copy(expectedSignature[:], expectedSig) - require.Equal(t, expectedSignature, signature) + require.Equal(t, expectedSig, signature[:]) }