Skip to content

Commit

Permalink
Add Attesation Contract (#69)
Browse files Browse the repository at this point in the history
Co-authored-by: Trajan0x <[email protected]>
  • Loading branch information
trajan0x and trajan0x authored Jul 30, 2022
1 parent 34733cc commit 9389ba6
Show file tree
Hide file tree
Showing 28 changed files with 4,931 additions and 21 deletions.
13 changes: 13 additions & 0 deletions core/agents/updater/producer.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,16 @@ func HashUpdate(update types.Update) ([32]byte, error) {
signedHash := crypto.Keccak256Hash([]byte("\x19Ethereum Signed Message:\n32"), hashedDigest.Bytes())
return signedHash, nil
}

// HashAttestation hashes an attestation.
func HashAttestation(attestation types.Attestation) ([32]byte, error) {
encodedAttestation, err := types.EncodeAttestation(attestation)
if err != nil {
return [32]byte{}, fmt.Errorf("could not encode attestation: %w", err)
}

hashedDigest := crypto.Keccak256Hash(encodedAttestation)

signedHash := crypto.Keccak256Hash([]byte("\x19Ethereum Signed Message:\n32"), hashedDigest.Bytes())
return signedHash, nil
}
3,443 changes: 3,443 additions & 0 deletions core/contracts/attestationcollector/attestationcollector.abigen.go

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions core/contracts/attestationcollector/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package attestationcollector

//go:generate go run github.com/synapsecns/sanguine/tools/abigen generate --sol ../../../packages/contracts/flattened/AttestationCollector.sol --pkg attestationcollector --sol-version 0.8.13 --filename attestationcollector
34 changes: 34 additions & 0 deletions core/contracts/attestationcollector/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package attestationcollector

import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
)

// AttestationCollectorRef is a bound attestatoin collector contract that returns the address of the attestation collector contract.
//nolint: golint
type AttestationCollectorRef struct {
*AttestationCollector
address common.Address
}

// Address gets the address of the attestation contract.
func (a AttestationCollectorRef) Address() common.Address {
return a.address
}

// NewAttestationCollectorRef creates an attestation contract with a contract ref.
func NewAttestationCollectorRef(address common.Address, backend bind.ContractBackend) (*AttestationCollectorRef, error) {
attestationContract, err := NewAttestationCollector(address, backend)
if err != nil {
return nil, err
}

return &AttestationCollectorRef{
AttestationCollector: attestationContract,
address: address,
}, nil
}

var _ vm.ContractRef = AttestationCollectorRef{}
848 changes: 848 additions & 0 deletions core/contracts/test/attestationharness/attestationharness.abigen.go

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions core/contracts/test/attestationharness/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package attestationharness

//go:generate go run github.com/synapsecns/sanguine/tools/abigen generate --sol ../../../../packages/contracts/flattened/AttestationHarness.sol --pkg attestationharness --sol-version 0.8.13 --filename attestationharness
// line after go:generate cannot be left blank
35 changes: 35 additions & 0 deletions core/contracts/test/attestationharness/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package attestationharness

import (
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
)

// AttestationHarnessRef is an attestation harness reference
//nolint: golint
type AttestationHarnessRef struct {
*AttestationHarness
address common.Address
}

// Address gets the address of the contract.
func (a AttestationHarnessRef) Address() common.Address {
return a.address
}

// NewAttestationHarnessRef creates a new attestation harness.
func NewAttestationHarnessRef(address common.Address, backend bind.ContractBackend) (*AttestationHarnessRef, error) {
contract, err := NewAttestationHarness(address, backend)
if err != nil {
return nil, fmt.Errorf("could not create home harness: %w", err)
}

return &AttestationHarnessRef{
AttestationHarness: contract,
address: address,
}, nil
}

var _ vm.ContractRef = &AttestationHarnessRef{}
6 changes: 3 additions & 3 deletions core/db/datastore/pebble/sdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func (d *pebbleDB) StoreLeaf(leafIndex uint32, destinationAndNonce uint64, leaf
return nil
}

// MessageByNonce retreives a raw committed message by its leaf hash.
// MessageByNonce retrieves a raw committed message by its leaf hash.
func (d *pebbleDB) MessageByNonce(destination, nonce uint32) (types.CommittedMessage, error) {
leaf, err := d.LeafByNonce(destination, nonce)
if err != nil {
Expand Down Expand Up @@ -223,7 +223,7 @@ func (d *pebbleDB) MessageByLeaf(leaf common.Hash) (types.CommittedMessage, erro
return committedMessage, nil
}

// LeafByNonce retreives the leaf hash keyed by destination and nonce.
// LeafByNonce retrieves the leaf hash keyed by destination and nonce.
func (d *pebbleDB) LeafByNonce(destination, nonce uint32) (common.Hash, error) {
destAndNonce := types.CombineDestinationAndNonce(destination, nonce)
value, _, err := d.DB.Get(d.FullKey(LEAF, []byte(fmt.Sprintf("%d", destAndNonce))))
Expand Down Expand Up @@ -252,7 +252,7 @@ func (d *pebbleDB) LeafByIndex(leafIndex uint32) (common.Hash, error) {
return common.BytesToHash(value), nil
}

// MessageByLeafIndex retreives a message by its leaf index.
// MessageByLeafIndex retrieves a message by its leaf index.
func (d *pebbleDB) MessageByLeafIndex(leafIndex uint32) (types.CommittedMessage, error) {
leaf, err := d.LeafByIndex(leafIndex)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions core/db/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (m *MessageSuite) TestStoresAndRetrievesMessages() {
})
}

func (m *MessageSuite) TestStoresAndRetreivesProofs() {
func (m *MessageSuite) TestStoresAndretrievesProofs() {
m.RunOnAllDBs(func(newDB db.MessageDB) {
leaf := common.BigToHash(big.NewInt(gofakeit.Int64()))
index := gofakeit.Uint32()
Expand Down Expand Up @@ -101,10 +101,10 @@ func (m *MessageSuite) TestStoreAndRetrieveLatestRoot() {
err = newDB.StoreLatestRoot(latestRoot)
Nil(m.T(), err)

retreivedRoot, err := newDB.RetrieveLatestRoot()
retrievedRoot, err := newDB.RetrieveLatestRoot()
Nil(m.T(), err)

Equal(m.T(), retreivedRoot, latestRoot)
Equal(m.T(), retrievedRoot, latestRoot)
})
}

Expand Down
4 changes: 2 additions & 2 deletions core/db/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type MessageDB interface {
StoreCommittedMessage(committedMessage types.CommittedMessage) error
// StoreLatestMessage stores a raw committed message building off the leaf index
StoreLatestMessage(committedMessage types.CommittedMessage) error
// MessageByNonce retreives a raw committed message by its leaf hash.
// MessageByNonce retrieves a raw committed message by its leaf hash.
MessageByNonce(destination, nonce uint32) (types.CommittedMessage, error)
// MessageByLeaf fetches a message by leaf
MessageByLeaf(leaf common.Hash) (types.CommittedMessage, error)
Expand All @@ -47,7 +47,7 @@ type MessageDB interface {
// GetMessageLatestBlockEnd gets the message latest block
GetMessageLatestBlockEnd() (height uint32, err error)

// RetrieveLatestRoot retreives latest root
// RetrieveLatestRoot retrieves latest root
RetrieveLatestRoot() (common.Hash, error)
// StoreLatestRoot stores the latest root
StoreLatestRoot(latestRoot common.Hash) error
Expand Down
7 changes: 6 additions & 1 deletion core/domains/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type DomainClient interface {
Config() config.DomainConfig
// BlockNumber gets the latest block
BlockNumber(ctx context.Context) (uint32, error)
// Home retreives a handle for the home contract
// Home retrieves a handle for the home contract
Home() HomeContract
}

Expand All @@ -36,5 +36,10 @@ type HomeContract interface {
Update(ctx context.Context, signer signer.Signer, update types.SignedUpdate) error
}

// AttestationCollectorContract contains the interface for the attestation collector.
type AttestationCollectorContract interface {
SubmitAttestation(signer signer.Signer, attestation types.SignedAttestation) error
}

// ErrNoUpdate indicates no update has been produced.
var ErrNoUpdate = errors.New("no update produced")
62 changes: 62 additions & 0 deletions core/domains/evm/collector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package evm

import (
"context"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/synapsecns/sanguine/core/contracts/attestationcollector"
"github.com/synapsecns/sanguine/core/domains"
"github.com/synapsecns/sanguine/core/types"
"github.com/synapsecns/sanguine/ethergo/signer/nonce"
"github.com/synapsecns/sanguine/ethergo/signer/signer"
"github.com/synapsecns/synapse-node/pkg/evm"
)

// NewAttestationCollectorContract returns a bound attestation collector contract.
func NewAttestationCollectorContract(ctx context.Context, client evm.Chain, attestationAddress common.Address) (domains.AttestationCollectorContract, error) {
boundCountract, err := attestationcollector.NewAttestationCollectorRef(attestationAddress, client)
if err != nil {
return nil, fmt.Errorf("could not create %T: %w", &attestationcollector.AttestationCollectorRef{}, err)
}

nonceManager := nonce.NewNonceManager(ctx, client, client.GetBigChainID())
return attestationCollectorContract{
contract: boundCountract,
client: client,
nonceManager: nonceManager,
}, nil
}

type attestationCollectorContract struct {
// contract contains the conract handle
contract *attestationcollector.AttestationCollectorRef
// client contains the evm client
client evm.Chain
// nonceManager is the nonce manager used for transacting with the chain
nonceManager nonce.Manager
}

// SubmitAttestation submits an attestation to the attestation collector.
func (a attestationCollectorContract) SubmitAttestation(signer signer.Signer, attestation types.SignedAttestation) error {
transactor, err := signer.GetTransactor(a.client.GetBigChainID())
if err != nil {
return fmt.Errorf("could not sign tx: %w", err)
}

transactOpts, err := a.nonceManager.NewKeyedTransactor(transactor)
if err != nil {
return fmt.Errorf("could not create tx: %w", err)
}

encodedAttestation, err := types.EncodeSignedAttestation(attestation)
if err != nil {
return fmt.Errorf("could not get signed attestations: %w", err)
}

_, err = a.contract.SubmitAttestation(transactOpts, transactOpts.From, encodedAttestation)
if err != nil {
return fmt.Errorf("could not submit attestation: %w", err)
}

return nil
}
35 changes: 35 additions & 0 deletions core/domains/evm/collector_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package evm_test

import (
"github.com/brianvoe/gofakeit/v6"
"github.com/ethereum/go-ethereum/common"
. "github.com/stretchr/testify/assert"
"github.com/synapsecns/sanguine/core/agents/updater"
pebble2 "github.com/synapsecns/sanguine/core/db/datastore/pebble"
"github.com/synapsecns/sanguine/core/domains/evm"
"github.com/synapsecns/sanguine/core/types"
"math/big"
)

func (i ContractSuite) TestSubmitAttestation() {
attestionCollector, err := evm.NewAttestationCollectorContract(i.GetTestContext(), i.attestationBackend, i.attestationContract.Address())
Nil(i.T(), err)

localDomain := attestationDomain
nonce := gofakeit.Uint32()
root := common.BigToHash(new(big.Int).SetUint64(gofakeit.Uint64()))

unsignedAttestation := types.NewAttestation(uint32(localDomain), nonce, root)
hashedAttestation, err := updater.HashAttestation(unsignedAttestation)
Nil(i.T(), err)

signature, err := i.signer.SignMessage(i.GetTestContext(), pebble2.ToSlice(hashedAttestation), false)
Nil(i.T(), err)

signedAttestation := types.NewSignedAttestation(unsignedAttestation, signature)

err = attestionCollector.SubmitAttestation(i.signer, signedAttestation)
Nil(i.T(), err)

// TODO retrieve once we have a way to
}
26 changes: 21 additions & 5 deletions core/domains/evm/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/ethereum/go-ethereum/params"
. "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/synapsecns/sanguine/core/contracts/attestationcollector"
"github.com/synapsecns/sanguine/core/contracts/home"
"github.com/synapsecns/sanguine/core/domains/evm"
"github.com/synapsecns/sanguine/core/testutil"
Expand Down Expand Up @@ -49,9 +50,11 @@ func TestEVMSuite(t *testing.T) {
// ContractSuite defines a suite for testing contracts. This uses the simulated backend.
type ContractSuite struct {
*testutils.TestSuite
homeContract *home.HomeRef
testBackend backends.SimulatedTestBackend
signer signer.Signer
homeContract *home.HomeRef
attestationContract *attestationcollector.AttestationCollectorRef
testBackend backends.SimulatedTestBackend
attestationBackend backends.SimulatedTestBackend
signer signer.Signer
}

func NewContractSuite(tb testing.TB) *ContractSuite {
Expand All @@ -61,19 +64,26 @@ func NewContractSuite(tb testing.TB) *ContractSuite {
}
}

const attestationDomain = 4

func (i *ContractSuite) SetupTest() {
i.TestSuite.SetupTest()

deployManager := testutil.NewDeployManager(i.T())
i.testBackend = simulated.NewSimulatedBackend(i.GetTestContext(), i.T())
i.testBackend = simulated.NewSimulatedBackendWithChainID(i.GetTestContext(), i.T(), big.NewInt(1))
i.attestationBackend = simulated.NewSimulatedBackendWithChainID(i.GetTestContext(), i.T(), big.NewInt(2))

_, i.homeContract = deployManager.GetHome(i.GetTestContext(), i.testBackend)

var attestationContract backends.DeployedContract
attestationContract, i.attestationContract = deployManager.GetAttestationCollector(i.GetTestContext(), i.attestationBackend)

wall, err := wallet.FromRandom()
Nil(i.T(), err)

i.signer = localsigner.NewSigner(wall.PrivateKey())
i.testBackend.FundAccount(i.GetTestContext(), wall.Address(), *big.NewInt(params.Ether))
i.attestationBackend.FundAccount(i.GetTestContext(), wall.Address(), *big.NewInt(params.Ether))

// change the updater as defined by the update manager contract
_, updaterManager := deployManager.GetUpdaterManager(i.GetTestContext(), i.testBackend)
Expand All @@ -85,8 +95,14 @@ func (i *ContractSuite) SetupTest() {
// set the signer address to the updater
tx, err := updaterManager.SetUpdater(transactOpts.TransactOpts, i.signer.Address())
Nil(i.T(), err)

i.testBackend.WaitForConfirmation(i.GetTestContext(), tx)

// add the updater to attestation contract
auth := i.attestationBackend.GetTxContext(i.GetTestContext(), attestationContract.OwnerPtr())

tx, err = i.attestationContract.AddUpdater(auth.TransactOpts, attestationDomain, i.signer.Address())
Nil(i.T(), err)
i.attestationBackend.WaitForConfirmation(i.GetTestContext(), tx)
}

func TestContractSuite(t *testing.T) {
Expand Down
Loading

0 comments on commit 9389ba6

Please sign in to comment.