-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Parser support for Destination and add DB models for monitoring (#…
- Loading branch information
1 parent
2871606
commit 8bce96e
Showing
21 changed files
with
999 additions
and
16 deletions.
There are no files selected for viewing
103 changes: 103 additions & 0 deletions
103
core/contracts/attestationcollector/attestationcollector_test.go
This file contains 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,103 @@ | ||
package attestationcollector_test | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"math/big" | ||
"time" | ||
|
||
"github.com/brianvoe/gofakeit/v6" | ||
"github.com/ethereum/go-ethereum/accounts/abi/bind" | ||
"github.com/ethereum/go-ethereum/common" | ||
. "github.com/stretchr/testify/assert" | ||
"github.com/synapsecns/sanguine/core/agents/notary" | ||
"github.com/synapsecns/sanguine/core/contracts/attestationcollector" | ||
"github.com/synapsecns/sanguine/core/types" | ||
"github.com/synapsecns/synapse-node/contracts/bridge" | ||
) | ||
|
||
func (a AttestationCollectorSuite) TestAttestationCollectorSuite() { | ||
// Set up the contexts for all contracts, including the destination and attestation collector to get owner. | ||
txContextOrigin := a.testBackendOrigin.GetTxContext(a.GetTestContext(), nil) | ||
txContextDestination := a.testBackendDestination.GetTxContext(a.GetTestContext(), a.destinationContractMetadata.OwnerPtr()) | ||
txContextAttestationCollector := a.testBackendDestination.GetTxContext(a.GetTestContext(), a.attestationContractMetadata.OwnerPtr()) | ||
|
||
// Create a channel and subscription to receive AttestationSubmitted events as they are emitted. | ||
attestationSink := make(chan *attestationcollector.AttestationCollectorAttestationSubmitted) | ||
subAttestation, err := a.attestationContract.WatchAttestationSubmitted(&bind.WatchOpts{Context: a.GetTestContext()}, attestationSink, []common.Address{}) | ||
Nil(a.T(), err) | ||
|
||
encodedTips, err := types.EncodeTips(types.NewTips(big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0))) | ||
Nil(a.T(), err) | ||
|
||
// Dispatch an event from the Origin contract to be accepted on the Destination contract. | ||
tx, err := a.originContract.Dispatch(txContextOrigin.TransactOpts, 1, [32]byte{}, 1, encodedTips, nil) | ||
Nil(a.T(), err) | ||
a.testBackendOrigin.WaitForConfirmation(a.GetTestContext(), tx) | ||
|
||
// Create an attestation | ||
localDomain := uint32(a.testBackendOrigin.Config().ChainID) | ||
nonce := gofakeit.Uint32() | ||
root := common.BigToHash(new(big.Int).SetUint64(gofakeit.Uint64())) | ||
unsignedAttestation := types.NewAttestation(localDomain, nonce, root) | ||
hashedAttestation, err := notary.HashAttestation(unsignedAttestation) | ||
Nil(a.T(), err) | ||
|
||
signature, err := a.signer.SignMessage(a.GetTestContext(), bridge.KappaToSlice(hashedAttestation), false) | ||
Nil(a.T(), err) | ||
|
||
signedAttestation := types.NewSignedAttestation(unsignedAttestation, signature) | ||
encodedSig, err := types.EncodeSignature(signedAttestation.Signature()) | ||
Nil(a.T(), err) | ||
|
||
attestation, err := a.attestationHarness.FormatAttestation( | ||
&bind.CallOpts{Context: a.GetTestContext()}, | ||
signedAttestation.Attestation().Domain(), | ||
signedAttestation.Attestation().Nonce(), | ||
signedAttestation.Attestation().Root(), | ||
encodedSig, | ||
) | ||
Nil(a.T(), err) | ||
|
||
// Set notary to the testing address so we can submit attestations. | ||
tx, err = a.destinationContract.SetNotary(txContextDestination.TransactOpts, uint32(a.testBackendOrigin.GetChainID()), a.signer.Address()) | ||
Nil(a.T(), err) | ||
a.testBackendDestination.WaitForConfirmation(a.GetTestContext(), tx) | ||
|
||
// Submit the attestation to get an AttestationAccepted event. | ||
tx, err = a.destinationContract.SubmitAttestation(txContextDestination.TransactOpts, attestation) | ||
Nil(a.T(), err) | ||
a.testBackendDestination.WaitForConfirmation(a.GetTestContext(), tx) | ||
|
||
// Set notary to the testing address so we can submit attestations. | ||
tx, err = a.attestationContract.AddNotary(txContextAttestationCollector.TransactOpts, uint32(a.testBackendOrigin.GetChainID()), a.signer.Address()) | ||
Nil(a.T(), err) | ||
a.testBackendDestination.WaitForConfirmation(a.GetTestContext(), tx) | ||
|
||
// Submit the attestation to get an AttestationSubmitted event. | ||
tx, err = a.attestationContract.SubmitAttestation(txContextAttestationCollector.TransactOpts, attestation) | ||
Nil(a.T(), err) | ||
a.testBackendDestination.WaitForConfirmation(a.GetTestContext(), tx) | ||
|
||
watchCtx, cancel := context.WithTimeout(a.GetTestContext(), time.Second*10) | ||
defer cancel() | ||
|
||
select { | ||
// check for errors and fail | ||
case <-watchCtx.Done(): | ||
a.T().Error(a.T(), fmt.Errorf("test context completed %w", a.GetTestContext().Err())) | ||
case <-subAttestation.Err(): | ||
a.T().Error(a.T(), subAttestation.Err()) | ||
// get AttestationSubmitted event | ||
case item := <-attestationSink: | ||
parser, err := attestationcollector.NewParser(a.attestationContract.Address()) | ||
Nil(a.T(), err) | ||
|
||
// Check to see if the event was an AttestationSubmitted event. | ||
eventType, ok := parser.EventType(item.Raw) | ||
True(a.T(), ok) | ||
Equal(a.T(), eventType, attestationcollector.AttestationSubmittedEvent) | ||
|
||
break | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains 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,83 @@ | ||
package attestationcollector | ||
|
||
import ( | ||
"fmt" | ||
"github.com/ethereum/go-ethereum/common" | ||
ethTypes "github.com/ethereum/go-ethereum/core/types" | ||
"github.com/synapsecns/sanguine/core/types" | ||
) | ||
|
||
// init serves as a static assertion that AllEventTypes are accounted for. | ||
func init() { | ||
if len(_EventType_index)-1 != len(AllEventTypes) { | ||
panic("add new events to alle vent types") | ||
} | ||
} | ||
|
||
// Parser parses events from the attestation collector contract. | ||
type Parser interface { | ||
// EventType determines if an event was initiated by the bridge or the user. | ||
EventType(log ethTypes.Log) (_ EventType, ok bool) | ||
// ParseAttestationSubmitted parses an AttestationSubmitted event | ||
ParseAttestationSubmitted(log ethTypes.Log) (_ types.AttestationSubmitted, ok bool) | ||
} | ||
|
||
type parserImpl struct { | ||
// filterer is the parser filterer we use to parse events | ||
filterer *AttestationCollectorFilterer | ||
} | ||
|
||
// NewParser creates a new parser for the attestation collector contract. | ||
func NewParser(attestationCollectorAddress common.Address) (Parser, error) { | ||
parser, err := NewAttestationCollectorFilterer(attestationCollectorAddress, nil) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not create %T: %w", AttestationCollectorFilterer{}, err) | ||
} | ||
|
||
return &parserImpl{filterer: parser}, nil | ||
} | ||
|
||
func (p parserImpl) EventType(log ethTypes.Log) (_ EventType, ok bool) { | ||
for _, logTopic := range log.Topics { | ||
eventType := eventTypeFromTopic(logTopic) | ||
if eventType == nil { | ||
continue | ||
} | ||
|
||
return *eventType, true | ||
} | ||
// return an unknown event to avoid cases where user failed to check the event type | ||
return EventType(len(AllEventTypes) + 2), false | ||
} | ||
|
||
// ParseAttestationSubmitted parses an AttestationSubmitted event. | ||
func (p parserImpl) ParseAttestationSubmitted(log ethTypes.Log) (_ types.AttestationSubmitted, ok bool) { | ||
attestation, err := p.filterer.ParseAttestationSubmitted(log) | ||
if err != nil { | ||
return nil, false | ||
} | ||
|
||
attestationSubmitted := types.NewAttestationSubmitted( | ||
attestation.Notary.Hash(), | ||
attestation.Attestation, | ||
) | ||
|
||
return attestationSubmitted, true | ||
} | ||
|
||
// EventType is the type of the attestation collector events | ||
//go:generate go run golang.org/x/tools/cmd/stringer -type=EventType | ||
type EventType uint | ||
|
||
const ( | ||
// AttestationSubmittedEvent is a AttestationSubmitted event. | ||
AttestationSubmittedEvent EventType = 0 | ||
) | ||
|
||
// Int gets the int for an event type. | ||
func (i EventType) Int() uint8 { | ||
return uint8(i) | ||
} | ||
|
||
// AllEventTypes contains all event types. | ||
var AllEventTypes = []EventType{AttestationSubmittedEvent} |
This file contains 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 @@ | ||
package attestationcollector_test | ||
|
||
import ( | ||
"math/big" | ||
"testing" | ||
|
||
"github.com/ethereum/go-ethereum/accounts/abi/bind" | ||
"github.com/ethereum/go-ethereum/params" | ||
"github.com/stretchr/testify/suite" | ||
"github.com/synapsecns/sanguine/core/contracts/attestationcollector" | ||
"github.com/synapsecns/sanguine/core/contracts/destination" | ||
"github.com/synapsecns/sanguine/core/contracts/origin" | ||
"github.com/synapsecns/sanguine/core/contracts/test/attestationharness" | ||
"github.com/synapsecns/sanguine/core/testutil" | ||
"github.com/synapsecns/sanguine/ethergo/signer/signer" | ||
"github.com/synapsecns/sanguine/ethergo/signer/signer/localsigner" | ||
"github.com/synapsecns/sanguine/ethergo/signer/wallet" | ||
"github.com/synapsecns/synapse-node/testutils" | ||
"github.com/synapsecns/synapse-node/testutils/backends" | ||
"github.com/synapsecns/synapse-node/testutils/backends/preset" | ||
) | ||
|
||
// AttestationCollectorSuite is the attestation collector test suite. | ||
type AttestationCollectorSuite struct { | ||
*testutils.TestSuite | ||
originContract *origin.OriginRef | ||
destinationContract *destination.DestinationRef | ||
destinationContractMetadata backends.DeployedContract | ||
attestationHarness *attestationharness.AttestationHarnessRef | ||
attestationContract *attestationcollector.AttestationCollectorRef | ||
attestationContractMetadata backends.DeployedContract | ||
testBackendOrigin backends.SimulatedTestBackend | ||
testBackendDestination backends.SimulatedTestBackend | ||
wallet wallet.Wallet | ||
signer signer.Signer | ||
} | ||
|
||
// NewAttestationCollectorSuite creates an end-to-end test suite. | ||
func NewAttestationCollectorSuite(tb testing.TB) *AttestationCollectorSuite { | ||
tb.Helper() | ||
return &AttestationCollectorSuite{ | ||
TestSuite: testutils.NewTestSuite(tb), | ||
} | ||
} | ||
|
||
func (a *AttestationCollectorSuite) SetupTest() { | ||
a.TestSuite.SetupTest() | ||
|
||
a.testBackendOrigin = preset.GetRinkeby().Geth(a.GetTestContext(), a.T()) | ||
a.testBackendDestination = preset.GetBSCTestnet().Geth(a.GetTestContext(), a.T()) | ||
deployManager := testutil.NewDeployManager(a.T()) | ||
|
||
_, a.originContract = deployManager.GetOrigin(a.GetTestContext(), a.testBackendOrigin) | ||
_, a.attestationHarness = deployManager.GetAttestationHarness(a.GetTestContext(), a.testBackendOrigin) | ||
a.attestationContractMetadata, a.attestationContract = deployManager.GetAttestationCollector(a.GetTestContext(), a.testBackendDestination) | ||
a.destinationContractMetadata, a.destinationContract = deployManager.GetDestination(a.GetTestContext(), a.testBackendDestination) | ||
|
||
var err error | ||
a.wallet, err = wallet.FromRandom() | ||
if err != nil { | ||
a.T().Fatal(err) | ||
} | ||
|
||
_, notaryManager := deployManager.GetNotaryManager(a.GetTestContext(), a.testBackendOrigin) | ||
owner, err := notaryManager.Owner(&bind.CallOpts{Context: a.GetTestContext()}) | ||
if err != nil { | ||
a.T().Fatal(err) | ||
} | ||
|
||
a.signer = localsigner.NewSigner(a.wallet.PrivateKey()) | ||
a.testBackendOrigin.FundAccount(a.GetTestContext(), a.signer.Address(), *big.NewInt(params.Ether)) | ||
a.testBackendDestination.FundAccount(a.GetTestContext(), a.signer.Address(), *big.NewInt(params.Ether)) | ||
|
||
transactOpts := a.testBackendOrigin.GetTxContext(a.GetTestContext(), &owner) | ||
|
||
tx, err := notaryManager.SetNotary(transactOpts.TransactOpts, a.signer.Address()) | ||
if err != nil { | ||
a.T().Fatal(err) | ||
} | ||
|
||
a.testBackendOrigin.WaitForConfirmation(a.GetTestContext(), tx) | ||
} | ||
|
||
// TestAttestationCollectorSuite runs the integration test suite. | ||
func TestAttestationCollectorSuite(t *testing.T) { | ||
suite.Run(t, NewAttestationCollectorSuite(t)) | ||
} |
This file contains 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,44 @@ | ||
package attestationcollector | ||
|
||
import ( | ||
"bytes" | ||
"strings" | ||
|
||
"github.com/ethereum/go-ethereum/accounts/abi" | ||
"github.com/ethereum/go-ethereum/common" | ||
) | ||
|
||
func init() { | ||
// set topics | ||
var err error | ||
|
||
parsedAttestationCollector, err := abi.JSON(strings.NewReader(AttestationCollectorABI)) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
AttestationSubmittedTopic = parsedAttestationCollector.Events["AttestationSubmitted"].ID | ||
} | ||
|
||
// AttestationSubmittedTopic is the topic that gets emitted | ||
// when the AttestationSubmitted event is called. | ||
var AttestationSubmittedTopic common.Hash | ||
|
||
// topicMap maps events to topics. | ||
// this is returned as a function to assert immutability. | ||
func topicMap() map[EventType]common.Hash { | ||
return map[EventType]common.Hash{ | ||
AttestationSubmittedEvent: AttestationSubmittedTopic, | ||
} | ||
} | ||
|
||
// eventTypeFromTopic gets the event type from the topic | ||
// returns nil if the topic is not found. | ||
func eventTypeFromTopic(ogTopic common.Hash) *EventType { | ||
for eventType, topic := range topicMap() { | ||
if bytes.Equal(ogTopic.Bytes(), topic.Bytes()) { | ||
return &eventType | ||
} | ||
} | ||
return nil | ||
} |
Oops, something went wrong.