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

Get signature endpoint #475

Closed
wants to merge 66 commits into from
Closed
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
e6219a2
base warp backend
Jan 19, 2023
b054615
add signature caching
Jan 19, 2023
183a5cd
add docs
Jan 20, 2023
6043c13
error handling
Jan 20, 2023
24fe40e
pr fixes
Jan 20, 2023
dc3e441
basic signature request
Jan 20, 2023
7820ec1
hash unsigned message for key
Jan 20, 2023
a2fa3a3
Merge branch 'warp-backend' into signature-handler
Jan 20, 2023
ff4d54d
implement new Request and RequestHandler interfaces
Jan 20, 2023
4f0403e
signature handler impl without constructing one
Jan 20, 2023
c729040
fix import
Jan 20, 2023
618a0de
Merge remote-tracking branch 'origin/master' into signature-handler
Jan 23, 2023
738d19e
quick pr fixes and merge
Jan 23, 2023
8d33345
quick pr fixes and merge
Jan 23, 2023
be5a4d6
Merge remote-tracking branch 'origin/master' into warp-backend
Jan 23, 2023
e8ac670
save signature instead of whole msg
Jan 23, 2023
bd75e6d
use avaGO cache
Jan 23, 2023
5d61bb0
rename warpBackend and docs
Jan 23, 2023
7b650b6
fix nits
Jan 23, 2023
41b86bf
Merge remote-tracking branch 'origin/master' into warp-backend
Jan 23, 2023
2cdd440
Merge branch 'warp-backend' into signature-handler
Jan 23, 2023
887fd6f
Update plugin/evm/warp_backend.go
Jan 23, 2023
7c8e06f
Update plugin/evm/warp_backend.go
Jan 23, 2023
b0f2ff3
fix pr nits
Jan 23, 2023
8fc39cd
pr fixes and testing
Jan 24, 2023
76a8a0e
type check for caching
Jan 24, 2023
4dc1d23
Merge branch 'warp-backend' into signature-handler
Jan 24, 2023
c745420
handlers and request before tests
Jan 24, 2023
17d1101
fix imports
Jan 24, 2023
4582f47
signature handler with stats and test
Jan 25, 2023
6a44563
use memdb and remove extra test
Jan 25, 2023
fb76223
remove unused
Jan 26, 2023
b7bfa17
fix imports
Jan 26, 2023
3d47a86
fix imports
Jan 26, 2023
ba6ee49
Merge remote-tracking branch 'origin/warp-backend' into signature-han…
Jan 26, 2023
cffb9cc
nit
Jan 26, 2023
005d90b
update license year
Jan 27, 2023
66a8238
use require noError
Jan 27, 2023
1389af4
Merge remote-tracking branch 'origin/master' into warp-backend
Jan 30, 2023
9a99797
saving message in db and pr fixes
Jan 30, 2023
67b7e6f
Merge branch 'warp-backend' into signature-handler
Jan 31, 2023
70e1d00
create noop signature handler and refactor code handler
Jan 31, 2023
de89d5b
get signature endpoint
cam-schultz Feb 1, 2023
562c8f0
add api arg to evm client
cam-schultz Feb 1, 2023
6d86d97
Merge remote-tracking branch 'origin/master' into signature-handler
Feb 2, 2023
76febba
Update sync/handlers/handler.go
Feb 2, 2023
48513b1
Merge branch 'signature-handler' of github.com:ava-labs/subnet-evm in…
Feb 2, 2023
ce25575
update backend return value
Feb 2, 2023
9d93fd1
refactor handlers to network handler
Feb 2, 2023
cfd843e
change constructor of handler stats
Feb 2, 2023
4b636e9
pr cleanups
Feb 2, 2023
9755d4f
warp api
cam-schultz Feb 6, 2023
cf5c907
initialize warp backend
cam-schultz Feb 6, 2023
656f286
Merge branch 'signature-handler' into get-signature-endpoint
cam-schultz Feb 6, 2023
fc668f9
build fix
cam-schultz Feb 6, 2023
dfcc95e
wip
cam-schultz Feb 7, 2023
cfcb650
warp api follows eth api pattern
cam-schultz Feb 7, 2023
0d4e895
cleanup and comments
cam-schultz Feb 7, 2023
cee8aa0
clean up response
cam-schultz Feb 8, 2023
93a43d0
fix warp client return type
cam-schultz Feb 8, 2023
453e543
nits for get-signature-endpoint (#502)
darioush Feb 9, 2023
ae7cdcf
Merge branch 'master' of github.com:ava-labs/subnet-evm into get-sign…
darioush Feb 9, 2023
6b46ff4
Merge branch 'get-signature-endpoint' of github.com:ava-labs/subnet-e…
darioush Feb 9, 2023
329dcb8
Merge branch 'master' into get-signature-endpoint
aaronbuchwald Feb 9, 2023
b0efb9d
resolve merge conflict
cam-schultz Feb 9, 2023
8626fc4
Merge branch 'get-signature-endpoint' of github.com:ava-labs/subnet-e…
cam-schultz 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) {
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