Skip to content

Commit

Permalink
Seperate lifecycle, still broken.
Browse files Browse the repository at this point in the history
  • Loading branch information
StefanIliev545 committed May 20, 2024
1 parent 9d3df2d commit e847563
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 39 deletions.
53 changes: 42 additions & 11 deletions contracts/generated/ManagementContract/ManagementContract.go

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions contracts/src/management/ManagementContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ contract ManagementContract is Initializable, OwnableUpgradeable {
MerkleTreeMessageBus.IMerkleTreeMessageBus public merkleMessageBus;
mapping(bytes32 =>bool) public isWithdrawalSpent;

bytes32 public lastBatchHash;

function initialize() public initializer {
__Ownable_init(msg.sender);
lastBatchSeqNo = 0;
Expand All @@ -76,7 +78,7 @@ contract ManagementContract is Initializable, OwnableUpgradeable {
}
}

function addCrossChainMessagesRoot(bytes32 root, bytes32 blockHash, uint256 blockNum, bytes[] memory crossChainHashes, bytes calldata signature) external {
function addCrossChainMessagesRoot(bytes32 _lastBatchHash, bytes32 blockHash, uint256 blockNum, bytes[] memory crossChainHashes, bytes calldata signature) external {
if (block.number > blockNum + 255) {
revert("Block binding too old");
}
Expand All @@ -85,9 +87,11 @@ contract ManagementContract is Initializable, OwnableUpgradeable {
revert(string(abi.encodePacked("Invalid block binding:", Strings.toString(block.number),":", Strings.toString(uint256(blockHash)), ":", Strings.toString(uint256(blockhash(blockNum))))));
}

address enclaveID = ECDSA.recover(keccak256(abi.encode(root, blockHash, blockNum, crossChainHashes)), signature);
address enclaveID = ECDSA.recover(keccak256(abi.encode(_lastBatchHash, blockHash, blockNum, crossChainHashes)), signature);
require(attested[enclaveID], "enclaveID not attested"); //todo: only sequencer, rather than everyone who has attested.

lastBatchHash = _lastBatchHash;

for(uint256 i = 0; i < crossChainHashes.length; i++) {
merkleMessageBus.addStateRoot(bytes32(crossChainHashes[i]), block.timestamp); //todo: change the activation time.
}
Expand Down
4 changes: 2 additions & 2 deletions go/common/crosschain.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

type ExtCrossChainBundle struct {
StateRootHash gethcommon.Hash
LastBatchHash gethcommon.Hash
Signature []byte
L1BlockHash gethcommon.Hash // The block hash that's expected to be canonical on signature submission
L1BlockNum *big.Int // The number of the block that has the block hash. This is used to verify the block hash.
Expand All @@ -37,7 +37,7 @@ func (bundle ExtCrossChainBundle) HashPacked() common.Hash {
},
}

bytes, err := args.Pack(bundle.StateRootHash, bundle.L1BlockHash, bundle.L1BlockNum, bundle.CrossChainHashes)
bytes, err := args.Pack(bundle.LastBatchHash, bundle.L1BlockHash, bundle.L1BlockNum, bundle.CrossChainHashes)
if err != nil {
panic(err)
}
Expand Down
6 changes: 5 additions & 1 deletion go/common/host/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,18 @@ type L1Publisher interface {
// PublishSecretResponse will create and publish a secret response tx to the management contract - fire and forget we don't wait for receipt
PublishSecretResponse(secretResponse *common.ProducedSecretResponse) error

PublishCrossChainBundle(bundle *common.ExtCrossChainBundle)
// PublishCrossChainBundle will create and publish a cross-chain bundle tx to the management contract
PublishCrossChainBundle(bundle *common.ExtCrossChainBundle) error

FetchLatestSeqNo() (*big.Int, error)

// GetImportantContracts returns a (cached) record of addresses of the important network contracts
GetImportantContracts() map[string]gethcommon.Address
// ResyncImportantContracts will fetch the latest important contracts from the management contract, update the cache
ResyncImportantContracts() error

// GetBundleRangeFromManagementContract returns the range of batches for which to build a bundle
GetBundleRangeFromManagementContract() (*big.Int, *big.Int, error)
}

// L2BatchRepository provides an interface for the host to request L2 batch data (live-streaming and historical)
Expand Down
3 changes: 2 additions & 1 deletion go/enclave/nodetype/sequencer.go
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ func (s *sequencer) ExportCrossChainData(ctx context.Context, fromSeqNo uint64,
}

blockHash := canonicalBatches[len(canonicalBatches)-1].Header.L1Proof
batchHash := canonicalBatches[len(canonicalBatches)-1].Header.Hash()

block, err := s.storage.FetchBlock(ctx, blockHash)
if err != nil {
Expand All @@ -502,7 +503,7 @@ func (s *sequencer) ExportCrossChainData(ctx context.Context, fromSeqNo uint64,
}

bundle := &common.ExtCrossChainBundle{
StateRootHash: gethcommon.BigToHash(gethcommon.Big0), // unused for now.
LastBatchHash: batchHash, // unused for now.
L1BlockHash: block.Hash(),
L1BlockNum: big.NewInt(0).Set(block.Header().Number),
CrossChainHashes: crossChainHashes,
Expand Down
42 changes: 33 additions & 9 deletions go/host/enclave/guardian.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ func (g *Guardian) Start() error {
// Note: after HA work this will need additional check that we are the **active** sequencer enclave
go g.periodicBatchProduction()
go g.periodicRollupProduction()
go g.periodicBundleSubmission()
}

// subscribe for L1 and P2P data
Expand Down Expand Up @@ -613,15 +614,6 @@ func (g *Guardian) periodicRollupProduction() {
// this method waits until the receipt is received
g.sl.L1Publisher().PublishRollup(producedRollup)
lastSuccessfulRollup = time.Now()

fromBatchNum := fromBatch
toBatchNum := producedRollup.Header.LastBatchSeqNo
bundle, err := g.enclaveClient.ExportCrossChainData(context.Background(), fromBatchNum, toBatchNum)
if err != nil {
g.logger.Error("Unable to export cross chain bundle from enclave", log.ErrKey, err)
continue
}
g.sl.L1Publisher().PublishCrossChainBundle(bundle)
}

case <-g.hostInterrupter.Done():
Expand All @@ -632,6 +624,38 @@ func (g *Guardian) periodicRollupProduction() {
}
}

func (g *Guardian) periodicBundleSubmission() {
defer g.logger.Info("Stopping bundle submission")

// check rollup every l1 block time
bundleSubmissionTicker := time.NewTicker(g.rollupInterval)

for {
select {
case <-bundleSubmissionTicker.C:
from, to, err := g.sl.L1Publisher().GetBundleRangeFromManagementContract()
if err != nil {
g.logger.Error("Unable to get bundle range from management contract", log.ErrKey, err)
continue
}
bundle, err := g.enclaveClient.ExportCrossChainData(context.Background(), from.Uint64(), to.Uint64())
if err != nil {
g.logger.Error("Unable to export cross chain bundle from enclave", log.ErrKey, err)
continue
}

err = g.sl.L1Publisher().PublishCrossChainBundle(bundle)
if err != nil {
g.logger.Error("Unable to publish cross chain bundle", log.ErrKey, err)
continue
}
case <-g.hostInterrupter.Done():
bundleSubmissionTicker.Stop()
return
}
}
}

func (g *Guardian) streamEnclaveData() {
defer g.logger.Info("Stopping enclave data stream")
g.logger.Info("Starting L2 update stream from enclave")
Expand Down
13 changes: 12 additions & 1 deletion go/host/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,18 @@ func NewHost(config *config.HostConfig, hostServices *ServicesRegistry, p2p host
hostServices.RegisterService(hostcommon.L1BlockRepositoryName, l1Repo)
maxWaitForL1Receipt := 6 * config.L1BlockTime // wait ~10 blocks to see if tx gets published before retrying
retryIntervalForL1Receipt := config.L1BlockTime // retry ~every block
l1Publisher := l1.NewL1Publisher(hostIdentity, ethWallet, ethClient, mgmtContractLib, l1Repo, host.stopControl, logger, maxWaitForL1Receipt, retryIntervalForL1Receipt)
l1Publisher := l1.NewL1Publisher(
hostIdentity,
ethWallet,
ethClient,
mgmtContractLib,
l1Repo,
host.stopControl,
logger,
maxWaitForL1Receipt,
retryIntervalForL1Receipt,
hostStorage,
)
hostServices.RegisterService(hostcommon.L1PublisherName, l1Publisher)
hostServices.RegisterService(hostcommon.L2BatchRepositoryName, l2Repo)
hostServices.RegisterService(hostcommon.EnclaveServiceName, enclService)
Expand Down
56 changes: 44 additions & 12 deletions go/host/l1/publisher.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/ten-protocol/go-ten/contracts/generated/ManagementContract"
"github.com/ten-protocol/go-ten/go/common/errutil"
"github.com/ten-protocol/go-ten/go/common/stopcontrol"
"github.com/ten-protocol/go-ten/go/host/storage"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
gethcommon "github.com/ethereum/go-ethereum/common"
Expand All @@ -31,6 +32,7 @@ type Publisher struct {
hostWallet wallet.Wallet // Wallet used to issue ethereum transactions
ethClient ethadapter.EthClient
mgmtContractLib mgmtcontractlib.MgmtContractLib // Library to handle Management Contract lib operations
storage storage.Storage

// cached map of important contract addresses (updated when we see a SetImportantContractsTx)
importantContractAddresses map[string]gethcommon.Address
Expand Down Expand Up @@ -62,6 +64,7 @@ func NewL1Publisher(
logger gethlog.Logger,
maxWaitForL1Receipt time.Duration,
retryIntervalForL1Receipt time.Duration,
storage storage.Storage,
) *Publisher {
sendingCtx, cancelSendingCtx := context.WithCancel(context.Background())
return &Publisher{
Expand All @@ -74,6 +77,7 @@ func NewL1Publisher(
logger: logger,
maxWaitForL1Receipt: maxWaitForL1Receipt,
retryIntervalForL1Receipt: retryIntervalForL1Receipt,
storage: storage,

importantContractAddresses: map[string]gethcommon.Address{},
importantAddressesMutex: sync.RWMutex{},
Expand All @@ -95,12 +99,38 @@ func (p *Publisher) Start() error {
return nil
}

func (p *Publisher) RunBundleSubmission() {
func (p *Publisher) GetBundleRangeFromManagementContract() (*big.Int, *big.Int, error) {
managementCtr, err := ManagementContract.NewManagementContract(*p.mgmtContractLib.GetContractAddr(), p.ethClient.EthClient())
if err != nil {
p.logger.Error("Unable to instantiate management contract client")
return
return nil, nil, err
}

lastBatchHash, err := managementCtr.LastBatchHash(&bind.CallOpts{})
if err != nil {
p.logger.Error("Unable to fetch last batch hash from management contract", log.ErrKey, err)
return nil, nil, err
}

var fromSeqNo *big.Int
if lastBatchHash == [32]byte{} {
fromSeqNo = big.NewInt(0)
} else {
batch, err := p.storage.FetchBatch(lastBatchHash)
if err != nil {
p.logger.Error("Unable to fetch last batch from host db", log.ErrKey, err)
return nil, nil, err
}
fromSeqNo = batch.SeqNo()
}

lastBatchRolledUpSeqNo, err := managementCtr.LastBatchSeqNo(&bind.CallOpts{})
if err != nil {
p.logger.Error("Unable to fetch last batch seq no from management contract", log.ErrKey, err)
return nil, nil, err
}

return fromSeqNo, lastBatchRolledUpSeqNo, nil
}

func (p *Publisher) Stop() error {
Expand Down Expand Up @@ -246,51 +276,53 @@ func (p *Publisher) PublishRollup(producedRollup *common.ExtRollup) {
}
}

func (p *Publisher) PublishCrossChainBundle(bundle *common.ExtCrossChainBundle) {
func (p *Publisher) PublishCrossChainBundle(bundle *common.ExtCrossChainBundle) error {
if p.mgmtContractLib.IsMock() {
return
return nil
}

if len(bundle.CrossChainHashes) == 0 {
return
return fmt.Errorf("nothing to publish in cross chain bundle")
}

managementCtr, err := ManagementContract.NewManagementContract(*p.mgmtContractLib.GetContractAddr(), p.ethClient.EthClient())
if err != nil {
p.logger.Error("Unable to instantiate management contract client")
return
return fmt.Errorf("unable to init")
}

transactor, err := bind.NewKeyedTransactorWithChainID(p.hostWallet.PrivateKey(), p.hostWallet.ChainID())
if err != nil {
p.logger.Error("Unable to create transactor for management contract")
return
return fmt.Errorf("unable to init")
}

nonce, err := p.ethClient.EthClient().PendingNonceAt(context.Background(), p.hostWallet.Address())
if err != nil {
p.logger.Error("Unable to get nonce for management contract", log.ErrKey, err)
return
return fmt.Errorf("unable to get nonce for management contract. Cause: %w", err)
}

// transactor.GasLimit = 200_000
transactor.Nonce = big.NewInt(0).SetUint64(nonce)

tx, err := managementCtr.AddCrossChainMessagesRoot(transactor, [32]byte(bundle.StateRootHash.Bytes()), bundle.L1BlockHash, bundle.L1BlockNum, bundle.CrossChainHashes, bundle.Signature)
tx, err := managementCtr.AddCrossChainMessagesRoot(transactor, [32]byte(bundle.LastBatchHash.Bytes()), bundle.L1BlockHash, bundle.L1BlockNum, bundle.CrossChainHashes, bundle.Signature)
if err != nil {
if !errors.Is(err, errutil.ErrCrossChainBundleRepublished) {
p.logger.Error("Error with submitting cross chain bundle transaction.", log.ErrKey, err, log.BundleHashKey, bundle.StateRootHash)
p.logger.Error("Error with submitting cross chain bundle transaction.", log.ErrKey, err, log.BundleHashKey, bundle.LastBatchHash)
}
p.hostWallet.SetNonce(p.hostWallet.GetNonce() - 1)
return
return fmt.Errorf("unable to submit cross chain bundle transaction. Cause: %w", err)
}

err = p.awaitTransaction(tx)
if err != nil {
p.logger.Error("Error with receipt of cross chain publish transaction", log.TxKey, tx.Hash(), log.ErrKey, err)
return fmt.Errorf("unable to get receipt for cross chain bundle transaction. Cause: %w", err)
}

p.logger.Info("Successfully submitted bundle", log.BundleHashKey, bundle.StateRootHash)
p.logger.Info("Successfully submitted bundle", log.BundleHashKey, bundle.LastBatchHash)
return nil
}

func (p *Publisher) GetImportantContracts() map[string]gethcommon.Address {
Expand Down

0 comments on commit e847563

Please sign in to comment.