-
Notifications
You must be signed in to change notification settings - Fork 269
Warp backend interface and implementation #452
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
Merged
Merged
Changes from all commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
e6219a2
base warp backend
b054615
add signature caching
183a5cd
add docs
6043c13
error handling
24fe40e
pr fixes
7820ec1
hash unsigned message for key
8d33345
quick pr fixes and merge
be5a4d6
Merge remote-tracking branch 'origin/master' into warp-backend
e8ac670
save signature instead of whole msg
bd75e6d
use avaGO cache
5d61bb0
rename warpBackend and docs
7b650b6
fix nits
41b86bf
Merge remote-tracking branch 'origin/master' into warp-backend
887fd6f
Update plugin/evm/warp_backend.go
7c8e06f
Update plugin/evm/warp_backend.go
b0f2ff3
fix pr nits
8fc39cd
pr fixes and testing
76a8a0e
type check for caching
17d1101
fix imports
6a44563
use memdb and remove extra test
fb76223
remove unused
b7bfa17
fix imports
1389af4
Merge remote-tracking branch 'origin/master' into warp-backend
9a99797
saving message in db and pr fixes
c19a004
Merge branch 'master' into warp-backend
16ddaee
update copyright
d115876
update backend variable naming
d61cc08
Merge branch 'master' into warp-backend
515d1e5
add comment about saving db vs cache
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// (c) 2023, Ava Labs, Inc. All rights reserved. | ||
// See the file LICENSE for licensing terms. | ||
|
||
package warp | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"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/hashing" | ||
"github.com/ava-labs/avalanchego/vms/platformvm/teleporter" | ||
) | ||
|
||
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. | ||
type WarpBackend interface { | ||
// 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. | ||
GetSignature(ctx context.Context, messageHash ids.ID) ([]byte, error) | ||
} | ||
|
||
// warpBackend implements WarpBackend, keeps track of warp messages, and generates message signatures. | ||
type warpBackend struct { | ||
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, db database.Database, signatureCacheSize int) WarpBackend { | ||
return &warpBackend{ | ||
db: db, | ||
snowCtx: snowCtx, | ||
signatureCache: &cache.LRU{Size: signatureCacheSize}, | ||
} | ||
} | ||
|
||
func (w *warpBackend) AddMessage(ctx context.Context, unsignedMessage *teleporter.UnsignedMessage) error { | ||
messageID := hashing.ComputeHash256Array(unsignedMessage.Bytes()) | ||
|
||
// In the case when a node restarts, and possibly changes its bls key, the cache gets emptied but the database does not. | ||
// So to avoid having incorrect signatures saved in the database after a bls key change, we save the full message in the database. | ||
// Whereas for the cache, after the node restart, the cache would be emptied so we can directly save the signatures. | ||
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) | ||
} | ||
|
||
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 { | ||
minghinmatthewlam marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return sig.([]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) | ||
} | ||
|
||
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 sign warp message: %w", err) | ||
} | ||
|
||
w.signatureCache.Put(messageID[:], signature) | ||
return signature, nil | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// (c) 2023, Ava Labs, Inc. All rights reserved. | ||
// See the file LICENSE for licensing terms. | ||
|
||
package warp | ||
|
||
import ( | ||
"context" | ||
"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" | ||
"github.com/ava-labs/avalanchego/utils/hashing" | ||
"github.com/ava-labs/avalanchego/vms/platformvm/teleporter" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
var ( | ||
sourceChainID = ids.GenerateTestID() | ||
destinationChainID = ids.GenerateTestID() | ||
payload = []byte("test") | ||
) | ||
|
||
func TestAddAndGetValidMessage(t *testing.T) { | ||
db := memdb.New() | ||
|
||
snowCtx := snow.DefaultContextTest() | ||
sk, err := bls.NewSecretKey() | ||
require.NoError(t, err) | ||
snowCtx.TeleporterSigner = teleporter.NewSigner(sk, sourceChainID) | ||
backend := 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 = backend.AddMessage(context.Background(), unsignedMsg) | ||
require.NoError(t, err) | ||
|
||
// Verify that a signature is returned successfully, and compare to expected signature. | ||
messageID := hashing.ComputeHash256Array(unsignedMsg.Bytes()) | ||
signature, err := backend.GetSignature(context.Background(), messageID) | ||
require.NoError(t, err) | ||
|
||
expectedSig, err := snowCtx.TeleporterSigner.Sign(unsignedMsg) | ||
require.NoError(t, err) | ||
require.Equal(t, expectedSig, signature) | ||
} | ||
|
||
func TestAddAndGetUnknownMessage(t *testing.T) { | ||
db := memdb.New() | ||
|
||
backend := 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 = backend.GetSignature(context.Background(), messageID) | ||
require.Error(t, err) | ||
} | ||
|
||
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. | ||
backend := 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 = backend.AddMessage(context.Background(), unsignedMsg) | ||
require.NoError(t, err) | ||
|
||
// Verify that a signature is returned successfully, and compare to expected signature. | ||
messageID := hashing.ComputeHash256Array(unsignedMsg.Bytes()) | ||
signature, err := backend.GetSignature(context.Background(), messageID) | ||
require.NoError(t, err) | ||
|
||
expectedSig, err := snowCtx.TeleporterSigner.Sign(unsignedMsg) | ||
require.NoError(t, err) | ||
require.Equal(t, expectedSig, signature) | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.