Skip to content
This repository has been archived by the owner on May 11, 2024. It is now read-only.

Commit

Permalink
refactor(driver, bindings): optimize assembling anchor transactions b…
Browse files Browse the repository at this point in the history
…y introducing `AnchorConstructor` and `FixedKSigner` structs && introduce `bindings.ProtocolConstants` (#59)
  • Loading branch information
davidtaikocha authored Dec 4, 2022
1 parent b5f74cf commit cc2fba6
Show file tree
Hide file tree
Showing 28 changed files with 453 additions and 629 deletions.
2 changes: 1 addition & 1 deletion bindings/.githead
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6ef307486711f17b3a3fb225055179525822b05d
0652595af38f17ed4bfc6e72bca64d2a6fb5616c
25 changes: 24 additions & 1 deletion bindings/constant.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,34 @@
package bindings

import (
"math/big"

"github.com/ethereum/go-ethereum/common"
)

var (
// Account address and private key of golden touch account.
// Account address and private key of golden touch account, defined in protocol's LibAnchorSignature.
// ref: https://github.com/taikoxyz/taiko-mono/blob/main/packages/protocol/contracts/libs/LibAnchorSignature.sol
GoldenTouchAddress = common.HexToAddress("0x0000777735367b36bC9B61C50022d9D0700dB4Ec")
GoldenTouchPrivKey = "0x92954368afd3caa1f3ce3ead0069c1af414054aefe1ef9aeacc1bf426222ce38"
)

// ProtocolConstants contains some constants used by Taiko protocol, defined in protocol's LibConstants.
// NOTE: this struct *MUST* match the return values of TaikoL1.getConstants method.
// ref: https://github.com/taikoxyz/taiko-mono/blob/main/packages/protocol/contracts/libs/LibConstants.sol
type ProtocolConstants struct {
ZKProofsPerBlock *big.Int // uint256 K_ZKPROOFS_PER_BLOCK
ChainID *big.Int // uint256 TAIKO_CHAIN_ID
MaxProposedBlocks *big.Int // uint256 TAIKO_MAX_PROPOSED_BLOCKS
MaxVerificationsPerTx *big.Int // uint256 TAIKO_MAX_VERIFICATIONS_PER_TX
CommitDelayConfirmations *big.Int // uint256 K_COMMIT_DELAY_CONFIRMATIONS
MaxProofsPerForkChoice *big.Int // uint256 TAIKO_MAX_PROOFS_PER_FORK_CHOICE
BlockMaxGasLimit *big.Int // uint256 TAIKO_BLOCK_MAX_GAS_LIMIT
BlockMaxTxs *big.Int // uint256 TAIKO_BLOCK_MAX_TXS
BlockDeadendHash common.Hash // bytes32 TAIKO_BLOCK_DEADEND_HASH
TxListMaxBytes *big.Int // uint256 TAIKO_TXLIST_MAX_BYTES
TxMinGasLimit *big.Int // uint256 TAIKO_TX_MIN_GAS_LIMIT
AnchorTxGasLimit *big.Int // uint256 V1_ANCHOR_TX_GAS_LIMIT
AnchorTxSelector [4]byte // bytes4 V1_ANCHOR_TX_SELECTOR
InvalidateBlockLogTopic [32]byte // bytes32 V1_INVALIDATE_BLOCK_LOG_TOPIC
}
18 changes: 0 additions & 18 deletions cmd/flags/proposer.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,29 +44,11 @@ var (
}
)

// Special flags for testing.
var (
ProduceInvalidBlocks = cli.BoolFlag{
Name: "produceInvalidBlocks",
Usage: "Special flag for testnet testing, if activated, the proposer will start producing bad blocks",
Hidden: true,
Category: proposerCategory,
}
ProduceInvalidBlocksInterval = cli.Uint64Flag{
Name: "produceInvalidBlocksInterval",
Usage: "Special flag for testnet testing, if activated, bad blocks will be produced every N valid blocks",
Hidden: true,
Category: proposerCategory,
}
)

// All proposer flags.
var ProposerFlags = MergeFlags(CommonFlags, []cli.Flag{
&L1ProposerPrivKey,
&L2SuggestedFeeRecipient,
&ProposeInterval,
&ProduceInvalidBlocks,
&ProduceInvalidBlocksInterval,
&ShufflePoolContent,
&CommitSlot,
})
58 changes: 0 additions & 58 deletions driver/anchor.go

This file was deleted.

112 changes: 112 additions & 0 deletions driver/anchor_constructor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package driver

import (
"context"
"fmt"
"math/big"

"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/taikoxyz/taiko-client/driver/signer"
"github.com/taikoxyz/taiko-client/pkg/rpc"
)

// AnchorConstructor is responsible for assembling the anchor transaction (V1TaikoL2.anchor) in
// each L2 block, which is always the first transaction.
type AnchorConstructor struct {
rpc *rpc.Client
gasLimit uint64
goldenTouchAddress common.Address
signer *signer.FixedKSigner
}

// NewAnchorConstructor creates a new AnchorConstructor instance.
func NewAnchorConstructor(
rpc *rpc.Client,
gasLimit uint64,
goldenTouchAddress common.Address,
goldenTouchPrivKey string,
) (*AnchorConstructor, error) {
signer, err := signer.NewFixedKSigner(goldenTouchPrivKey)
if err != nil {
return nil, fmt.Errorf("invalid golden touch private key %s", goldenTouchPrivKey)
}

return &AnchorConstructor{
rpc: rpc,
gasLimit: gasLimit,
goldenTouchAddress: goldenTouchAddress,
signer: signer,
}, nil
}

// AssembleAnchorTx assembles a signed TaikoL2.anchor transaction.
func (c *AnchorConstructor) AssembleAnchorTx(
ctx context.Context,
// Parameters of the TaikoL2.anchor transaction.
l1Height *big.Int,
l1Hash common.Hash,
// Height of the L2 block which including the TaikoL2.anchor transaction.
l2Height *big.Int,
) (*types.Transaction, error) {
opts, err := c.transactOpts(ctx, l2Height)
if err != nil {
return nil, err
}

return c.rpc.TaikoL2.Anchor(opts, l1Height, l1Hash)
}

// transactOpts is a utility method to create some transact options of the anchor transaction in given L2 block with
// golden touch account's private key.
func (c *AnchorConstructor) transactOpts(ctx context.Context, l2Height *big.Int) (*bind.TransactOpts, error) {
signer := types.LatestSignerForChainID(c.rpc.L2ChainID)

// Get the nonce of golden touch account at the specified height.
nonce, err := c.rpc.L2AccountNonce(ctx, c.goldenTouchAddress, l2Height)
if err != nil {
return nil, err
}

return &bind.TransactOpts{
From: c.goldenTouchAddress,
Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) {
if address != c.goldenTouchAddress {
return nil, bind.ErrNotAuthorized
}
signature, err := c.signTxPayload(signer.Hash(tx).Bytes())
if err != nil {
return nil, err
}
return tx.WithSignature(signer, signature)
},
Nonce: new(big.Int).SetUint64(nonce),
Context: ctx,
GasPrice: common.Big0,
GasLimit: c.gasLimit,
NoSend: true,
}, nil
}

// signTxPayload calculates an ECDSA signature for an anchor transaction.
// ref: https://github.com/taikoxyz/taiko-mono/blob/main/packages/protocol/contracts/libs/LibAnchorSignature.sol
func (c *AnchorConstructor) signTxPayload(hash []byte) ([]byte, error) {
if len(hash) != 32 {
return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash))
}

// Try k = 1.
sig, ok := c.signer.SignWithK(new(secp256k1.ModNScalar).SetInt(1))(hash)
if !ok {
// Try k = 2.
sig, ok = c.signer.SignWithK(new(secp256k1.ModNScalar).SetInt(2))(hash)
if !ok {
log.Crit("Failed to sign V1TaikoL2.anchor transaction using K = 1 and K = 2")
}
}

return sig[:], nil
}
62 changes: 62 additions & 0 deletions driver/anchor_constructor_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package driver

import (
"context"
"math/rand"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/taikoxyz/taiko-client/bindings"
"github.com/taikoxyz/taiko-client/testutils"
)

func (s *DriverTestSuite) TestNewAnchorTransactor() {
gasLimit := rand.Uint64()
c, err := NewAnchorConstructor(
s.RpcClient,
gasLimit, bindings.GoldenTouchAddress,
bindings.GoldenTouchPrivKey,
)
s.Nil(err)

opts, err := c.transactOpts(context.Background(), common.Big0)
s.Nil(err)
s.Equal(true, opts.NoSend)
s.Equal(gasLimit, opts.GasLimit)
s.Equal(common.Big0, opts.GasPrice)
s.Equal(common.Big0, opts.Nonce)
s.Equal(bindings.GoldenTouchAddress, opts.From)
}

func (s *DriverTestSuite) TestSign() {
// Payload 1
hash := hexutil.MustDecode("0x44943399d1507f3ce7525e9be2f987c3db9136dc759cb7f92f742154196868b9")
signatureBytes := testutils.SignatureFromRSV(
"0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
"0x782a1e70872ecc1a9f740dd445664543f8b7598c94582720bca9a8c48d6a4766",
1,
)
pubKey, err := crypto.Ecrecover(hash, signatureBytes)
s.Nil(err)
isVsalid := crypto.VerifySignature(pubKey, hash, signatureBytes[:64])
s.True(isVsalid)
signed, err := s.d.l2ChainSyncer.anchorConstructor.signTxPayload(hash)
s.Nil(err)
s.Equal(signatureBytes, signed)

// Payload 2
hash = hexutil.MustDecode("0x663d210fa6dba171546498489de1ba024b89db49e21662f91bf83cdffe788820")
signatureBytes = testutils.SignatureFromRSV(
"0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
"0x568130fab1a3a9e63261d4278a7e130588beb51f27de7c20d0258d38a85a27ff",
1,
)
pubKey, err = crypto.Ecrecover(hash, signatureBytes)
s.Nil(err)
isVsalid = crypto.VerifySignature(pubKey, hash, signatureBytes[:64])
s.True(isVsalid)
signed, err = s.d.l2ChainSyncer.anchorConstructor.signTxPayload(hash)
s.Nil(err)
s.Equal(signatureBytes, signed)
}
17 changes: 0 additions & 17 deletions driver/anchor_test.go

This file was deleted.

1 change: 1 addition & 0 deletions driver/beacon_syncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func (s *L2ChainSyncer) TriggerBeaconSync() error {
return fmt.Errorf("unexpected ForkchoiceUpdate response status: %s", status.Status)
}

// Update sync status.
s.beaconSyncTriggered = true
s.lastSyncedVerifiedBlockHash = lastVerifiedHeadPayload.BlockHash
s.lastSyncedVerifiedBlockID = blockID
Expand Down
6 changes: 4 additions & 2 deletions driver/block_inserter.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import (
txListValidator "github.com/taikoxyz/taiko-client/pkg/tx_list_validator"
)

// onBlockProposed is a `BlockProposed` event callback which responsible for
// inserting the proposed block one by one to the L2 execution engine.
func (s *L2ChainSyncer) onBlockProposed(
ctx context.Context,
event *bindings.TaikoL1ClientBlockProposed,
Expand Down Expand Up @@ -190,7 +192,7 @@ func (s *L2ChainSyncer) insertNewHead(
}

// Assemble a TaikoL2.anchor transaction
anchorTx, err := s.assembleAnchorTx(
anchorTx, err := s.anchorConstructor.AssembleAnchorTx(
ctx,
event.Meta.L1Height,
event.Meta.L1Hash,
Expand Down Expand Up @@ -305,7 +307,7 @@ func (s *L2ChainSyncer) createExecutionPayloads(
BlockMetadata: &beacon.BlockMetadata{
HighestBlockID: headBlockID,
Beneficiary: event.Meta.Beneficiary,
GasLimit: event.Meta.GasLimit + s.state.anchorTxGasLimit.Uint64(),
GasLimit: event.Meta.GasLimit + s.protocolConstants.AnchorTxGasLimit.Uint64(),
Timestamp: event.Meta.Timestamp,
TxList: txListBytes,
MixHash: event.Meta.MixHash,
Expand Down
Loading

0 comments on commit cc2fba6

Please sign in to comment.