Skip to content

Commit

Permalink
Supports ACP-118 messages (code sync from subnet-evm) (ava-labs#624)
Browse files Browse the repository at this point in the history
  • Loading branch information
darioush authored and oxbee committed Nov 6, 2024
1 parent f77f15f commit 7b7395c
Show file tree
Hide file tree
Showing 7 changed files with 409 additions and 10 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ require (
github.com/mattn/go-colorable v0.1.13
github.com/mattn/go-isatty v0.0.17
github.com/olekukonko/tablewriter v0.0.5
github.com/prometheus/client_golang v1.14.0
github.com/prometheus/client_golang v1.16.0
github.com/prometheus/client_model v0.3.0
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/spf13/cast v1.5.0
Expand Down Expand Up @@ -119,7 +119,7 @@ require (
go.opentelemetry.io/otel/sdk v1.22.0 // indirect
go.opentelemetry.io/otel/trace v1.22.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/term v0.18.0 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -453,8 +453,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
Expand Down Expand Up @@ -584,8 +584,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
Expand Down
12 changes: 8 additions & 4 deletions plugin/evm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
"github.com/ava-labs/coreth/trie"
"github.com/ava-labs/coreth/utils"
"github.com/ava-labs/coreth/warp"
"github.com/ava-labs/coreth/warp/handlers"
warpValidators "github.com/ava-labs/coreth/warp/validators"

// Force-load tracer engine to trigger registration
Expand Down Expand Up @@ -645,7 +646,6 @@ func (vm *VM) Initialize(

go vm.ctx.Log.RecoverAndPanic(vm.startContinuousProfiler)

// The Codec explicitly registers the types it requires from the secp256k1fx
// so [vm.baseCodec] is a dummy codec use to fulfill the secp256k1fx VM
// interface. The fx will register all of its types, which can be safely
// ignored by the VM's codec.
Expand All @@ -655,7 +655,7 @@ func (vm *VM) Initialize(
return err
}

vm.initializeStateSyncServer()
vm.initializeHandlers()
return vm.initializeStateSyncClient(lastAcceptedHeight)
}

Expand Down Expand Up @@ -793,14 +793,18 @@ func (vm *VM) initializeStateSyncClient(lastAcceptedHeight uint64) error {
return nil
}

// initializeStateSyncServer should be called after [vm.chain] is initialized.
func (vm *VM) initializeStateSyncServer() {
// initializeHandlers should be called after [vm.chain] is initialized.
func (vm *VM) initializeHandlers() {
vm.StateSyncServer = NewStateSyncServer(&stateSyncServerConfig{
Chain: vm.blockChain,
AtomicTrie: vm.atomicTrie,
SyncableInterval: vm.config.StateSyncCommitInterval,
})

// Add p2p warp message warpHandler
warpHandler := handlers.NewSignatureRequestHandlerP2P(vm.warpBackend, vm.networkCodec)
vm.Network.AddHandler(p2p.SignatureRequestHandlerID, warpHandler)

vm.setAppRequestHandlers()
vm.setCrossChainAppRequestHandler()
}
Expand Down
2 changes: 2 additions & 0 deletions warp/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ type Backend interface {
GetBlockSignature(blockID ids.ID) ([bls.SignatureLen]byte, error)

// GetMessage retrieves the [unsignedMessage] from the warp backend database if available
// TODO: After E-Upgrade, the backend no longer needs to store the mapping from messageHash
// to unsignedMessage (and this method can be removed).
GetMessage(messageHash ids.ID) (*avalancheWarp.UnsignedMessage, error)

// Clear clears the entire db
Expand Down
1 change: 1 addition & 0 deletions warp/handlers/signature_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
)

// SignatureRequestHandler serves warp signature requests. It is a peer.RequestHandler for message.MessageSignatureRequest.
// TODO: After E-Upgrade, this handler can be removed and SignatureRequestHandlerP2P is sufficient.
type SignatureRequestHandler struct {
backend warp.Backend
codec codec.Manager
Expand Down
160 changes: 160 additions & 0 deletions warp/handlers/signature_request_p2p.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// (c) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package handlers

import (
"context"
"fmt"
"time"

"github.com/ava-labs/avalanchego/codec"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/network/p2p"
"github.com/ava-labs/avalanchego/proto/pb/sdk"
"github.com/ava-labs/avalanchego/snow/engine/common"
"github.com/ava-labs/avalanchego/utils/crypto/bls"
avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp"
"github.com/ava-labs/avalanchego/vms/platformvm/warp/payload"
"github.com/ava-labs/coreth/warp"
"google.golang.org/protobuf/proto"
)

var _ p2p.Handler = (*SignatureRequestHandlerP2P)(nil)

const (
ErrFailedToParse = iota
ErrFailedToGetSig
ErrFailedToMarshal
)

// SignatureRequestHandlerP2P serves warp signature requests using the p2p
// framework from avalanchego. It is a peer.RequestHandler for
// message.MessageSignatureRequest.
type SignatureRequestHandlerP2P struct {
backend warp.Backend
codec codec.Manager
stats *handlerStats
}

func NewSignatureRequestHandlerP2P(backend warp.Backend, codec codec.Manager) *SignatureRequestHandlerP2P {
return &SignatureRequestHandlerP2P{
backend: backend,
codec: codec,
stats: newStats(),
}
}

func (s *SignatureRequestHandlerP2P) AppRequest(
ctx context.Context,
nodeID ids.NodeID,
deadline time.Time,
requestBytes []byte,
) ([]byte, *common.AppError) {
// Per ACP-118, the requestBytes are the serialized form of
// sdk.SignatureRequest.
req := new(sdk.SignatureRequest)
if err := proto.Unmarshal(requestBytes, req); err != nil {
return nil, &common.AppError{
Code: ErrFailedToParse,
Message: "failed to unmarshal request: " + err.Error(),
}
}

unsignedMessage, err := avalancheWarp.ParseUnsignedMessage(req.Message)
if err != nil {
return nil, &common.AppError{
Code: ErrFailedToParse,
Message: "failed to parse unsigned message: " + err.Error(),
}
}
parsed, err := payload.Parse(unsignedMessage.Payload)
if err != nil {
return nil, &common.AppError{
Code: ErrFailedToParse,
Message: "failed to parse payload: " + err.Error(),
}
}

var sig [bls.SignatureLen]byte
switch p := parsed.(type) {
case *payload.AddressedCall:
// Note we pass the unsigned message ID to GetMessageSignature since
// that is what the backend expects.
// However, we verify the types and format of the payload to ensure
// the message conforms to the ACP-118 spec.
sig, err = s.GetMessageSignature(unsignedMessage.ID())
if err != nil {
s.stats.IncMessageSignatureMiss()
} else {
s.stats.IncMessageSignatureHit()
}
case *payload.Hash:
sig, err = s.GetBlockSignature(p.Hash)
if err != nil {
s.stats.IncBlockSignatureMiss()
} else {
s.stats.IncBlockSignatureHit()
}
default:
return nil, &common.AppError{
Code: ErrFailedToParse,
Message: fmt.Sprintf("unknown payload type: %T", p),
}
}
if err != nil {
return nil, &common.AppError{
Code: ErrFailedToGetSig,
Message: "failed to get signature: " + err.Error(),
}
}

// Per ACP-118, the responseBytes are the serialized form of
// sdk.SignatureResponse.
resp := &sdk.SignatureResponse{Signature: sig[:]}
respBytes, err := proto.Marshal(resp)
if err != nil {
return nil, &common.AppError{
Code: ErrFailedToMarshal,
Message: "failed to marshal response: " + err.Error(),
}
}
return respBytes, nil
}

func (s *SignatureRequestHandlerP2P) GetMessageSignature(messageID ids.ID) ([bls.SignatureLen]byte, error) {
startTime := time.Now()
s.stats.IncMessageSignatureRequest()

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

return s.backend.GetMessageSignature(messageID)
}

func (s *SignatureRequestHandlerP2P) GetBlockSignature(blockID ids.ID) ([bls.SignatureLen]byte, error) {
startTime := time.Now()
s.stats.IncBlockSignatureRequest()

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

return s.backend.GetBlockSignature(blockID)
}

func (s *SignatureRequestHandlerP2P) CrossChainAppRequest(
ctx context.Context,
chainID ids.ID,
deadline time.Time,
requestBytes []byte,
) ([]byte, error) {
return nil, nil
}

func (s *SignatureRequestHandlerP2P) AppGossip(
ctx context.Context, nodeID ids.NodeID, gossipBytes []byte) {
}
Loading

0 comments on commit 7b7395c

Please # to comment.