Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Signature Request Handler #459

Merged
merged 59 commits into from
Feb 9, 2023
Merged
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
e6219a2
base warp backend
minghinmatthewlam Jan 19, 2023
b054615
add signature caching
minghinmatthewlam Jan 19, 2023
183a5cd
add docs
minghinmatthewlam Jan 20, 2023
6043c13
error handling
minghinmatthewlam Jan 20, 2023
24fe40e
pr fixes
minghinmatthewlam Jan 20, 2023
dc3e441
basic signature request
minghinmatthewlam Jan 20, 2023
7820ec1
hash unsigned message for key
minghinmatthewlam Jan 20, 2023
a2fa3a3
Merge branch 'warp-backend' into signature-handler
minghinmatthewlam Jan 20, 2023
ff4d54d
implement new Request and RequestHandler interfaces
minghinmatthewlam Jan 20, 2023
4f0403e
signature handler impl without constructing one
minghinmatthewlam Jan 20, 2023
c729040
fix import
minghinmatthewlam Jan 20, 2023
618a0de
Merge remote-tracking branch 'origin/master' into signature-handler
minghinmatthewlam Jan 23, 2023
738d19e
quick pr fixes and merge
minghinmatthewlam Jan 23, 2023
8d33345
quick pr fixes and merge
minghinmatthewlam Jan 23, 2023
be5a4d6
Merge remote-tracking branch 'origin/master' into warp-backend
minghinmatthewlam Jan 23, 2023
e8ac670
save signature instead of whole msg
minghinmatthewlam Jan 23, 2023
bd75e6d
use avaGO cache
minghinmatthewlam Jan 23, 2023
5d61bb0
rename warpBackend and docs
minghinmatthewlam Jan 23, 2023
7b650b6
fix nits
minghinmatthewlam Jan 23, 2023
41b86bf
Merge remote-tracking branch 'origin/master' into warp-backend
minghinmatthewlam Jan 23, 2023
2cdd440
Merge branch 'warp-backend' into signature-handler
minghinmatthewlam Jan 23, 2023
887fd6f
Update plugin/evm/warp_backend.go
minghinmatthewlam Jan 23, 2023
7c8e06f
Update plugin/evm/warp_backend.go
minghinmatthewlam Jan 23, 2023
b0f2ff3
fix pr nits
minghinmatthewlam Jan 23, 2023
8fc39cd
pr fixes and testing
minghinmatthewlam Jan 24, 2023
76a8a0e
type check for caching
minghinmatthewlam Jan 24, 2023
4dc1d23
Merge branch 'warp-backend' into signature-handler
minghinmatthewlam Jan 24, 2023
c745420
handlers and request before tests
minghinmatthewlam Jan 24, 2023
17d1101
fix imports
minghinmatthewlam Jan 24, 2023
4582f47
signature handler with stats and test
minghinmatthewlam Jan 25, 2023
6a44563
use memdb and remove extra test
minghinmatthewlam Jan 25, 2023
fb76223
remove unused
minghinmatthewlam Jan 26, 2023
b7bfa17
fix imports
minghinmatthewlam Jan 26, 2023
3d47a86
fix imports
minghinmatthewlam Jan 26, 2023
ba6ee49
Merge remote-tracking branch 'origin/warp-backend' into signature-han…
minghinmatthewlam Jan 26, 2023
cffb9cc
nit
minghinmatthewlam Jan 26, 2023
005d90b
update license year
minghinmatthewlam Jan 27, 2023
66a8238
use require noError
minghinmatthewlam Jan 27, 2023
1389af4
Merge remote-tracking branch 'origin/master' into warp-backend
minghinmatthewlam Jan 30, 2023
9a99797
saving message in db and pr fixes
minghinmatthewlam Jan 30, 2023
67b7e6f
Merge branch 'warp-backend' into signature-handler
minghinmatthewlam Jan 31, 2023
70e1d00
create noop signature handler and refactor code handler
minghinmatthewlam Jan 31, 2023
6d86d97
Merge remote-tracking branch 'origin/master' into signature-handler
minghinmatthewlam Feb 2, 2023
76febba
Update sync/handlers/handler.go
minghinmatthewlam Feb 2, 2023
48513b1
Merge branch 'signature-handler' of github.com:ava-labs/subnet-evm in…
minghinmatthewlam Feb 2, 2023
ce25575
update backend return value
minghinmatthewlam Feb 2, 2023
9d93fd1
refactor handlers to network handler
minghinmatthewlam Feb 2, 2023
cfd843e
change constructor of handler stats
minghinmatthewlam Feb 2, 2023
4b636e9
pr cleanups
minghinmatthewlam Feb 2, 2023
62f250f
signature request test for noop signature request handler
minghinmatthewlam Feb 6, 2023
3679478
remove tree changes
minghinmatthewlam Feb 7, 2023
5c08d07
fix pr comments
minghinmatthewlam Feb 7, 2023
56dc93b
Signature handler refactor (#495)
aaronbuchwald Feb 7, 2023
8e7ce7f
Merge remote-tracking branch 'origin/master' into signature-handler
minghinmatthewlam Feb 7, 2023
1f99cb1
pr fixes
minghinmatthewlam Feb 8, 2023
b9fdd83
Merge branch 'master' into signature-handler
minghinmatthewlam Feb 8, 2023
943da39
resolve conflicts merge master
minghinmatthewlam Feb 8, 2023
36eee41
add verify stats for nil count
minghinmatthewlam Feb 8, 2023
38a64a6
Signature handler nits (#501)
darioush Feb 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions handlers/handler.go
Original file line number Diff line number Diff line change
@@ -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/avalanchego/ids"
"github.com/ava-labs/subnet-evm/handlers/stats"
"github.com/ava-labs/subnet-evm/metrics"
"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 *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,
networkCodec codec.Manager,
) message.RequestHandler {
handlerStats := stats.NewHandlerStats(metrics.Enabled)
return &networkHandler{
// 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{},
}
}

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)
}
75 changes: 75 additions & 0 deletions handlers/signature_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// (c) 2023, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package handlers

import (
"context"
"time"

"github.com/ava-labs/avalanchego/codec"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/subnet-evm/handlers/stats"
"github.com/ava-labs/subnet-evm/plugin/evm/message"
"github.com/ava-labs/subnet-evm/plugin/evm/warp"
"github.com/ethereum/go-ethereum/log"
)

// SignatureRequestHandler is a peer.RequestHandler for message.SignatureRequest
// serving requested BLS signature data
type SignatureRequestHandler interface {
OnSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error)
}

// signatureRequestHandler implements the SignatureRequestHandler interface
type signatureRequestHandler struct {
backend warp.WarpBackend
codec codec.Manager
stats stats.SignatureRequestHandlerStats
}

func NewSignatureRequestHandler(backend warp.WarpBackend, codec codec.Manager, stats stats.SignatureRequestHandlerStats) SignatureRequestHandler {
return &signatureRequestHandler{
backend: backend,
codec: codec,
stats: stats,
}
}

// OnSignatureRequest handles message.SignatureRequest, and retrieves a warp signature for the requested message ID.
// Never returns an error
// Expects returned errors to be treated as FATAL
// Returns empty response if signature is not found
// Assumes ctx is active
func (s *signatureRequestHandler) OnSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) {
startTime := time.Now()
s.stats.IncSignatureRequest()

// Always report signature request time
defer func() {
s.stats.UpdateSignatureRequestTime(time.Since(startTime))
}()

signature, err := s.backend.GetSignature(ctx, signatureRequest.MessageID)
if err != nil {
log.Debug("Unknown warp signature requested", "messageID", signatureRequest.MessageID)
s.stats.IncSignatureMiss()
return nil, nil
}

s.stats.IncSignatureHit()
response := message.SignatureResponse{Signature: signature}
responseBytes, err := s.codec.Marshal(message.Version, response)
if err != nil {
log.Warn("could not marshal SignatureResponse, dropping request", "nodeID", nodeID, "requestID", requestID, "err", err)
return nil, nil
}

return responseBytes, nil
}

type NoopSignatureRequestHandler struct{}

func (s *NoopSignatureRequestHandler) OnSignatureRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, signatureRequest message.SignatureRequest) ([]byte, error) {
return nil, nil
}
99 changes: 99 additions & 0 deletions handlers/signature_request_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// (c) 2023, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package handlers

import (
"context"
"testing"
"time"

"github.com/ava-labs/avalanchego/database/memdb"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/snow"
"github.com/ava-labs/avalanchego/utils/crypto/bls"
"github.com/ava-labs/avalanchego/utils/hashing"
"github.com/ava-labs/avalanchego/vms/platformvm/teleporter"
"github.com/ava-labs/subnet-evm/handlers/stats"
"github.com/ava-labs/subnet-evm/plugin/evm/message"
"github.com/ava-labs/subnet-evm/plugin/evm/warp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestSignatureHandler(t *testing.T) {
minghinmatthewlam marked this conversation as resolved.
Show resolved Hide resolved
database := memdb.New()
snowCtx := snow.DefaultContextTest()
blsSecretKey, err := bls.NewSecretKey()
require.NoError(t, err)

snowCtx.TeleporterSigner = teleporter.NewSigner(blsSecretKey, snowCtx.ChainID)
warpBackend := warp.NewWarpBackend(snowCtx, database, 100)

msg, err := teleporter.NewUnsignedMessage(snowCtx.ChainID, snowCtx.CChainID, []byte("test"))
require.NoError(t, err)

messageID := hashing.ComputeHash256Array(msg.Bytes())
require.NoError(t, warpBackend.AddMessage(context.Background(), msg))
signature, err := warpBackend.GetSignature(context.Background(), messageID)
require.NoError(t, err)
unknownMessageID := ids.GenerateTestID()

mockHandlerStats := &stats.MockHandlerStats{}
signatureRequestHandler := NewSignatureRequestHandler(warpBackend, message.Codec, mockHandlerStats)

tests := map[string]struct {
setup func() (request message.SignatureRequest, expectedResponse []byte)
verifyStats func(t *testing.T, stats *stats.MockHandlerStats)
}{
"normal": {
setup: func() (request message.SignatureRequest, expectedResponse []byte) {
return message.SignatureRequest{
MessageID: messageID,
}, signature[:]
},
verifyStats: func(t *testing.T, stats *stats.MockHandlerStats) {
assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestCount)
assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestHit)
assert.Greater(t, mockHandlerStats.SignatureRequestDuration, time.Duration(0))
},
},
"unknown": {
setup: func() (request message.SignatureRequest, expectedResponse []byte) {
return message.SignatureRequest{
MessageID: unknownMessageID,
}, nil
},
verifyStats: func(t *testing.T, stats *stats.MockHandlerStats) {
assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestCount)
assert.EqualValues(t, 1, mockHandlerStats.SignatureRequestMiss)
assert.Greater(t, mockHandlerStats.SignatureRequestDuration, time.Duration(0))
},
},
}

for name, test := range tests {
// Reset stats before each test
mockHandlerStats.Reset()

t.Run(name, func(t *testing.T) {
request, expectedResponse := test.setup()
responseBytes, err := signatureRequestHandler.OnSignatureRequest(context.Background(), ids.GenerateTestNodeID(), 1, request)
assert.NoError(t, err)

// If the expected response is empty, assert that the handler returns an empty response and return early.
if len(expectedResponse) == 0 {
assert.Len(t, responseBytes, 0, "expected response to be empty")
return
}
var response message.SignatureResponse
_, err = message.Codec.Unmarshal(responseBytes, &response)
require.NoError(t, err, "error unmarshalling SignatureResponse")

var expectedSignature [bls.SignatureLen]byte
copy(expectedSignature[:], expectedResponse)
assert.Equal(t, expectedSignature, response.Signature)
test.verifyStats(t, mockHandlerStats)
})
}
}
Loading