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

Commit

Permalink
feat(proposer): update proposer based on protocol changes
Browse files Browse the repository at this point in the history
  • Loading branch information
davidtaikocha committed Sep 29, 2023
1 parent 8a59293 commit 330b92f
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 92 deletions.
80 changes: 42 additions & 38 deletions proposer/proposer.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,8 @@ type Proposer struct {
rpc *rpc.Client

// Private keys and account addresses
l1ProposerPrivKey *ecdsa.PrivateKey
l1ProposerAddress common.Address
l2SuggestedFeeRecipient common.Address
proposerPrivKey *ecdsa.PrivateKey
proposerAddress common.Address

// Proposing configurations
proposingInterval *time.Duration
Expand Down Expand Up @@ -88,9 +87,8 @@ func (p *Proposer) InitFromCli(ctx context.Context, c *cli.Context) error {

// InitFromConfig initializes the proposer instance based on the given configurations.
func InitFromConfig(ctx context.Context, p *Proposer, cfg *Config) (err error) {
p.l1ProposerPrivKey = cfg.L1ProposerPrivKey
p.l1ProposerAddress = crypto.PubkeyToAddress(cfg.L1ProposerPrivKey.PublicKey)
p.l2SuggestedFeeRecipient = cfg.L2SuggestedFeeRecipient
p.proposerPrivKey = cfg.L1ProposerPrivKey
p.proposerAddress = crypto.PubkeyToAddress(cfg.L1ProposerPrivKey.PublicKey)
p.proposingInterval = cfg.ProposeInterval
p.proposeEmptyBlocksInterval = cfg.ProposeEmptyBlocksInterval
p.proposeBlockTxGasLimit = cfg.ProposeBlockTxGasLimit
Expand Down Expand Up @@ -232,7 +230,7 @@ func (p *Proposer) ProposeOp(ctx context.Context) error {

txLists, err := p.rpc.GetPoolContent(
ctx,
p.L2SuggestedFeeRecipient(),
p.proposerAddress,
baseFee,
p.protocolConfigs.BlockMaxGasLimit,
p.protocolConfigs.BlockMaxTxListBytes.Uint64(),
Expand Down Expand Up @@ -282,7 +280,7 @@ func (p *Proposer) ProposeOp(ctx context.Context) error {
}
nonce, err := p.rpc.L1.NonceAt(
ctx,
crypto.PubkeyToAddress(p.l1ProposerPrivKey.PublicKey),
crypto.PubkeyToAddress(p.proposerPrivKey.PublicKey),
new(big.Int).SetUint64(head),
)
if err != nil {
Expand All @@ -305,13 +303,7 @@ func (p *Proposer) ProposeOp(ctx context.Context) error {
}

txNonce := nonce + uint64(i)
if err := p.ProposeTxList(ctx, &encoding.TaikoL1BlockMetadataInput{
Proposer: p.l2SuggestedFeeRecipient,
TxListHash: crypto.Keccak256Hash(txListBytes),
TxListByteStart: common.Big0,
TxListByteEnd: new(big.Int).SetUint64(uint64(len(txListBytes))),
CacheTxListInfo: false,
}, txListBytes, uint(txs.Len()), &txNonce); err != nil {
if err := p.ProposeTxList(ctx, txListBytes, uint(txs.Len()), &txNonce); err != nil {
return fmt.Errorf("failed to propose transactions: %w", err)
}

Expand All @@ -336,19 +328,14 @@ func (p *Proposer) ProposeOp(ctx context.Context) error {
// sendProposeBlockTx tries to send a TaikoL1.proposeBlock transaction.
func (p *Proposer) sendProposeBlockTx(
ctx context.Context,
meta *encoding.TaikoL1BlockMetadataInput,
txListBytes []byte,
nonce *uint64,
assignment []byte,
assignment *encoding.ProverAssignment,
fee *big.Int,
isReplacement bool,
) (*types.Transaction, error) {
// Propose the transactions list
inputs, err := encoding.EncodeProposeBlockInput(meta)
if err != nil {
return nil, err
}
opts, err := getTxOpts(ctx, p.rpc.L1, p.l1ProposerPrivKey, p.rpc.L1ChainID, fee)
opts, err := getTxOpts(ctx, p.rpc.L1, p.proposerPrivKey, p.rpc.L1ChainID, fee)
if err != nil {
return nil, err
}
Expand All @@ -363,15 +350,26 @@ func (p *Proposer) sendProposeBlockTx(
ctx,
p.rpc,
opts,
p.l1ProposerAddress,
p.proposerAddress,
new(big.Int).SetUint64(p.txReplacementTipMultiplier),
p.proposeBlockTxGasTipCap,
); err != nil {
return nil, err
}
}

proposeTx, err := p.rpc.TaikoL1.ProposeBlock(opts, inputs, assignment, txListBytes)
encodedssignment, err := encoding.EncodeProverAssignment(assignment)
if err != nil {
return nil, err
}

proposeTx, err := p.rpc.TaikoL1.ProposeBlock(
opts,
crypto.Keccak256Hash(txListBytes),
rpc.StringToBytes32(p.cfg.ExtraData),
encodedssignment,
txListBytes,
)
if err != nil {
return nil, encoding.TryParsingCustomError(err)
}
Expand All @@ -386,7 +384,11 @@ func (p *Proposer) ProposeTxList(
txNum uint,
nonce *uint64,
) error {
assignment, fee, err := p.proverSelector.AssignProver(ctx, meta)
signature, prover, fee, err := p.proverSelector.AssignProver(
ctx,
[]*encoding.TierFee{}, // TODO: update tier fees
crypto.Keccak256Hash(txListBytes),
)
if err != nil {
return err
}
Expand All @@ -400,7 +402,20 @@ func (p *Proposer) ProposeTxList(
if ctx.Err() != nil {
return nil
}
if tx, err = p.sendProposeBlockTx(ctx, meta, txListBytes, nonce, assignment, fee, isReplacement); err != nil {
if tx, err = p.sendProposeBlockTx(
ctx,
txListBytes,
nonce,
&encoding.ProverAssignment{
Prover: prover,
FeeToken: common.Address{},
TierFees: []*encoding.TierFee{}, // TODO: update tier fees
Expiry: uint64(proverAssignmentTimeout.Seconds()),
Signature: signature,
},
fee,
isReplacement,
); err != nil {
log.Warn("Failed to send propose block transaction", "error", encoding.TryParsingCustomError(err))
if strings.Contains(err.Error(), core.ErrNonceTooLow.Error()) {
return nil
Expand Down Expand Up @@ -446,13 +461,7 @@ func (p *Proposer) ProposeTxList(

// ProposeEmptyBlockOp performs a proposing one empty block operation.
func (p *Proposer) ProposeEmptyBlockOp(ctx context.Context) error {
return p.ProposeTxList(ctx, &encoding.TaikoL1BlockMetadataInput{
TxListHash: crypto.Keccak256Hash([]byte{}),
Proposer: p.L2SuggestedFeeRecipient(),
TxListByteStart: common.Big0,
TxListByteEnd: common.Big0,
CacheTxListInfo: false,
}, []byte{}, 0, nil)
return p.ProposeTxList(ctx, []byte{}, 0, nil)
}

// updateProposingTicker updates the internal proposing timer.
Expand All @@ -478,11 +487,6 @@ func (p *Proposer) Name() string {
return "proposer"
}

// L2SuggestedFeeRecipient returns the L2 suggested fee recipient of the current proposer.
func (p *Proposer) L2SuggestedFeeRecipient() common.Address {
return p.l2SuggestedFeeRecipient
}

// getTxOpts creates a bind.TransactOpts instance using the given private key.
func getTxOpts(
ctx context.Context,
Expand Down
40 changes: 16 additions & 24 deletions proposer/proposer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ func (s *ProposerTestSuite) TestProposeOp() {
_, isPending, err := s.p.rpc.L1.TransactionByHash(context.Background(), event.Raw.TxHash)
s.Nil(err)
s.False(isPending)
s.Equal(s.p.l2SuggestedFeeRecipient, event.Meta.Proposer)

receipt, err := s.p.rpc.L1.TransactionReceipt(context.Background(), event.Raw.TxHash)
s.Nil(err)
Expand Down Expand Up @@ -132,14 +131,14 @@ func (s *ProposerTestSuite) TestSendProposeBlockTx() {
opts, err := getTxOpts(
context.Background(),
s.p.rpc.L1,
s.p.l1ProposerPrivKey,
s.p.proposerPrivKey,
s.RpcClient.L1ChainID,
fee,
)
s.Nil(err)
s.Greater(opts.GasTipCap.Uint64(), uint64(0))

nonce, err := s.RpcClient.L1.PendingNonceAt(context.Background(), s.p.l1ProposerAddress)
nonce, err := s.RpcClient.L1.PendingNonceAt(context.Background(), s.p.proposerAddress)
s.Nil(err)

tx := types.NewTransaction(
Expand All @@ -154,31 +153,32 @@ func (s *ProposerTestSuite) TestSendProposeBlockTx() {
s.SetL1Automine(false)
defer s.SetL1Automine(true)

signedTx, err := types.SignTx(tx, types.LatestSignerForChainID(s.RpcClient.L1ChainID), s.p.l1ProposerPrivKey)
signedTx, err := types.SignTx(tx, types.LatestSignerForChainID(s.RpcClient.L1ChainID), s.p.proposerPrivKey)
s.Nil(err)
s.Nil(s.RpcClient.L1.SendTransaction(context.Background(), signedTx))

var emptyTxs []types.Transaction
encoded, err := rlp.EncodeToBytes(emptyTxs)
s.Nil(err)

meta := &encoding.TaikoL1BlockMetadataInput{
Proposer: s.p.L2SuggestedFeeRecipient(),
TxListHash: crypto.Keccak256Hash(encoded),
TxListByteStart: common.Big0,
TxListByteEnd: new(big.Int).SetUint64(uint64(len(encoded))),
CacheTxListInfo: false,
}

assignment, fee, err := s.p.proverSelector.AssignProver(context.Background(), meta)
signature, prover, fee, err := s.p.proverSelector.AssignProver(
context.Background(),
[]*encoding.TierFee{},
testutils.RandomHash(),
)
s.Nil(err)

newTx, err := s.p.sendProposeBlockTx(
context.Background(),
meta,
encoded,
&nonce,
assignment,
&encoding.ProverAssignment{
Prover: prover,
FeeToken: common.Address{},
TierFees: []*encoding.TierFee{},
Expiry: uint64(proverAssignmentTimeout.Seconds()),
Signature: signature,
},
fee,
true,
)
Expand All @@ -187,18 +187,10 @@ func (s *ProposerTestSuite) TestSendProposeBlockTx() {
}

func (s *ProposerTestSuite) TestAssignProverSuccessFirstRound() {
meta := &encoding.TaikoL1BlockMetadataInput{
Proposer: s.p.L2SuggestedFeeRecipient(),
TxListHash: testutils.RandomHash(),
TxListByteStart: common.Big0,
TxListByteEnd: common.Big0,
CacheTxListInfo: false,
}

s.SetL1Automine(false)
defer s.SetL1Automine(true)

_, fee, err := s.p.proverSelector.AssignProver(context.Background(), meta)
_, _, fee, err := s.p.proverSelector.AssignProver(context.Background(), []*encoding.TierFee{}, testutils.RandomHash())

s.Nil(err)
s.Equal(fee.Uint64(), s.p.cfg.BlockProposalFee.Uint64())
Expand Down
60 changes: 32 additions & 28 deletions proposer/prover_selector/eth_fee_eoa_selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,16 @@ func (s *ETHFeeEOASelector) ProverEndpoints() []*url.URL { return s.proverEndpoi
// AssignProver tries to pick a prover through the registered prover endpoints.
func (s *ETHFeeEOASelector) AssignProver(
ctx context.Context,
meta *encoding.TaikoL1BlockMetadataInput,
) ([]byte, *big.Int, error) {
tierFees []*encoding.TierFee,
txListHash common.Hash,
) ([]byte, common.Address, *big.Int, error) {
oracleProverAddress, err := s.rpc.TaikoL1.Resolve0(
&bind.CallOpts{Context: ctx},
rpc.StringToBytes32("oracle_prover"),
true,
)
if err != nil {
return nil, nil, err
return nil, common.Address{}, nil, err
}
// Iterate over each configured endpoint, and see if someone wants to accept this block.
// If it is denied, we continue on to the next endpoint.
Expand All @@ -111,10 +112,11 @@ func (s *ETHFeeEOASelector) AssignProver(
for _, endpoint := range s.shuffleProverEndpoints() {
encodedAssignment, proverAddress, err := assignProver(
ctx,
meta,
endpoint,
fee,
expiry,
tierFees,
txListHash,
s.requestTimeout,
oracleProverAddress,
)
Expand All @@ -123,22 +125,20 @@ func (s *ETHFeeEOASelector) AssignProver(
continue
}

if proverAddress != encoding.OracleProverAddress {
ok, err := rpc.CheckProverBalance(ctx, s.rpc, proverAddress, s.taikoL1Address, s.protocolConfigs.ProofBond)
if err != nil {
log.Warn("Failed to check prover balance", "endpoint", endpoint, "error", err)
continue
}
if !ok {
continue
}
ok, err := rpc.CheckProverBalance(ctx, s.rpc, proverAddress, s.taikoL1Address, s.protocolConfigs.LivenessBond)
if err != nil {
log.Warn("Failed to check prover balance", "endpoint", endpoint, "error", err)
continue
}
if !ok {
continue
}

return encodedAssignment, fee, nil
return encodedAssignment, proverAddress, fee, nil
}
}

return nil, nil, errUnableToFindProver
return nil, common.Address{}, nil, errUnableToFindProver
}

// shuffleProverEndpoints shuffles the current selector's prover endpoints.
Expand All @@ -152,10 +152,11 @@ func (s *ETHFeeEOASelector) shuffleProverEndpoints() []*url.URL {
// assignProver tries to assign a proof generation task to the given prover by HTTP API.
func assignProver(
ctx context.Context,
meta *encoding.TaikoL1BlockMetadataInput,
endpoint *url.URL,
fee *big.Int,
expiry uint64,
tierFees []*encoding.TierFee,
txListHash common.Hash,
timeout time.Duration,
oracleProverAddress common.Address,
) ([]byte, common.Address, error) {
Expand All @@ -164,13 +165,19 @@ func assignProver(
"endpoint", endpoint,
"fee", fee.String(),
"expiry", expiry,
"txListHash", txListHash,
)

// Send the HTTP request
var (
client = resty.New()
reqBody = &encoding.ProposeBlockData{Expiry: expiry, Input: *meta, Fee: fee}
result = server.ProposeBlockResponse{}
reqBody = &server.CreateAssignmentRequestBody{
FeeToken: (common.Address{}),
TierFees: tierFees,
Expiry: expiry,
TxListHash: txListHash,
}
result = server.ProposeBlockResponse{}
)
requestUrl, err := url.JoinPath(endpoint.String(), "/assignment")
if err != nil {
Expand All @@ -196,12 +203,12 @@ func assignProver(

// Ensure prover in response is the same as the one recovered
// from the signature
encodedBlockData, err := encoding.EncodeProposeBlockData(reqBody)
payload, err := encoding.EncodeProverAssignmentPayload(txListHash, common.Address{}, expiry, tierFees)
if err != nil {
return nil, common.Address{}, err
}

pubKey, err := crypto.SigToPub(crypto.Keccak256Hash(encodedBlockData).Bytes(), result.SignedPayload)
pubKey, err := crypto.SigToPub(crypto.Keccak256Hash(payload).Bytes(), result.SignedPayload)
if err != nil {
return nil, common.Address{}, err
}
Expand All @@ -217,15 +224,12 @@ func assignProver(
// Convert signature to one solidity can recover by adding 27 to 65th byte
result.SignedPayload[64] = uint8(uint(result.SignedPayload[64])) + 27

// If this assignment is to oracle prover, change prover address in assignment to `LibUtils.ORACLE_PROVER`
if oracleProverAddress != (common.Address{}) && result.Prover == oracleProverAddress {
result.Prover = encoding.OracleProverAddress
}

encoded, err := encoding.EncodeProverAssignment(&encoding.ProverAssignment{
Prover: result.Prover,
Expiry: reqBody.Expiry,
Data: result.SignedPayload,
Prover: result.Prover,
FeeToken: common.Address{},
TierFees: []*encoding.TierFee{}, // TODO: update tier fees
Expiry: reqBody.Expiry,
Signature: result.SignedPayload,
})
if err != nil {
return nil, common.Address{}, err
Expand Down
Loading

0 comments on commit 330b92f

Please sign in to comment.