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

Commit b6ea3ad

Browse files
authored
feat(eip4844): Eip4844 blob tx (#527)
2 parents 7aacb28 + 4614b95 commit b6ea3ad

File tree

4 files changed

+220
-4
lines changed

4 files changed

+220
-4
lines changed

pkg/rpc/txblob.go

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package rpc
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"github.com/ethereum/go-ethereum"
7+
"github.com/ethereum/go-ethereum/accounts/abi/bind"
8+
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
9+
"github.com/ethereum/go-ethereum/core/types"
10+
"github.com/ethereum/go-ethereum/crypto/kzg4844"
11+
"github.com/holiman/uint256"
12+
"math/big"
13+
)
14+
15+
func (c *EthClient) TransactBlobTx(opts *bind.TransactOpts, data []byte) (*types.Transaction, error) {
16+
// Sign the transaction and schedule it for execution
17+
if opts.Signer == nil {
18+
return nil, errors.New("no signer to authorize the transaction with")
19+
}
20+
// Create blob tx.
21+
rawTx, err := c.createBlobTx(opts, data)
22+
if err != nil {
23+
return nil, err
24+
}
25+
signedTx, err := opts.Signer(opts.From, rawTx)
26+
if err != nil {
27+
return nil, err
28+
}
29+
if opts.NoSend {
30+
return signedTx, nil
31+
}
32+
if err := c.SendTransaction(opts.Context, signedTx); err != nil {
33+
return nil, err
34+
}
35+
return signedTx, nil
36+
}
37+
38+
func (c *EthClient) createBlobTx(opts *bind.TransactOpts, data []byte) (*types.Transaction, error) {
39+
header, err := c.HeaderByNumber(opts.Context, nil)
40+
if err != nil {
41+
return nil, err
42+
}
43+
// Estimate TipCap
44+
gasTipCap := opts.GasTipCap
45+
if gasTipCap == nil {
46+
tip, err := c.SuggestGasTipCap(opts.Context)
47+
if err != nil {
48+
return nil, err
49+
}
50+
gasTipCap = tip
51+
}
52+
// Estimate FeeCap
53+
gasFeeCap := opts.GasFeeCap
54+
if gasFeeCap == nil {
55+
gasFeeCap = new(big.Int).Add(
56+
gasTipCap,
57+
new(big.Int).Mul(header.BaseFee, big.NewInt(2)),
58+
)
59+
}
60+
if gasFeeCap.Cmp(gasTipCap) < 0 {
61+
return nil, fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", gasFeeCap, gasTipCap)
62+
}
63+
// Estimate GasLimit
64+
gasLimit := opts.GasLimit
65+
if opts.GasLimit == 0 {
66+
var err error
67+
gasLimit, err = c.EstimateGas(nil, ethereum.CallMsg{
68+
From: opts.From,
69+
To: nil,
70+
GasPrice: nil,
71+
GasTipCap: gasTipCap,
72+
GasFeeCap: gasFeeCap,
73+
Value: nil,
74+
Data: nil,
75+
})
76+
if err != nil {
77+
return nil, err
78+
}
79+
}
80+
// create the transaction
81+
nonce, err := c.getNonce(opts)
82+
if err != nil {
83+
return nil, err
84+
}
85+
chainID, err := c.ChainID(opts.Context)
86+
if err != nil {
87+
return nil, err
88+
}
89+
90+
sidecar, err := makeSidecarWithSingleBlob(data)
91+
if err != nil {
92+
return nil, err
93+
}
94+
95+
var blobFeeCap uint64 = 100066
96+
if header.ExcessBlobGas != nil {
97+
blobFeeCap = *header.ExcessBlobGas
98+
}
99+
100+
baseTx := &types.BlobTx{
101+
ChainID: uint256.NewInt(chainID.Uint64()),
102+
Nonce: nonce,
103+
GasTipCap: uint256.NewInt(gasTipCap.Uint64()),
104+
GasFeeCap: uint256.NewInt(gasFeeCap.Uint64()),
105+
Gas: gasLimit,
106+
BlobFeeCap: uint256.MustFromBig(eip4844.CalcBlobFee(blobFeeCap)),
107+
BlobHashes: sidecar.BlobHashes(),
108+
Sidecar: sidecar,
109+
}
110+
return types.NewTx(baseTx), nil
111+
}
112+
113+
func (c *EthClient) getNonce(opts *bind.TransactOpts) (uint64, error) {
114+
if opts.Nonce == nil {
115+
return c.PendingNonceAt(opts.Context, opts.From)
116+
} else {
117+
return opts.Nonce.Uint64(), nil
118+
}
119+
}
120+
121+
func makeSidecarWithSingleBlob(data []byte) (*types.BlobTxSidecar, error) {
122+
if len(data) > BlobBytes {
123+
return nil, fmt.Errorf("data is bigger than 128k")
124+
}
125+
blob := kzg4844.Blob{}
126+
copy(blob[:], data)
127+
commitment, err := kzg4844.BlobToCommitment(blob)
128+
if err != nil {
129+
return nil, err
130+
}
131+
proof, err := kzg4844.ComputeBlobProof(blob, commitment)
132+
if err != nil {
133+
return nil, err
134+
}
135+
return &types.BlobTxSidecar{
136+
Blobs: []kzg4844.Blob{blob},
137+
Commitments: []kzg4844.Commitment{commitment},
138+
Proofs: []kzg4844.Proof{proof},
139+
}, nil
140+
}

pkg/rpc/txblob_test.go

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package rpc
2+
3+
import (
4+
"context"
5+
"os"
6+
"testing"
7+
"time"
8+
9+
"github.com/ethereum/go-ethereum/accounts/abi/bind"
10+
"github.com/ethereum/go-ethereum/common"
11+
"github.com/ethereum/go-ethereum/crypto"
12+
"github.com/stretchr/testify/assert"
13+
)
14+
15+
func TestBlockTx(t *testing.T) {
16+
ctx, cancel := context.WithCancel(context.Background())
17+
defer cancel()
18+
19+
url := "https://rpc.ankr.com/eth_goerli" //os.Getenv("L1_NODE_WS_ENDPOINT")
20+
l1Client, err := NewEthClient(ctx, url, time.Second*20)
21+
assert.NoError(t, err)
22+
23+
priv := os.Getenv("L1_PROPOSER_PRIVATE_KEY")
24+
sk, err := crypto.ToECDSA(common.FromHex(priv))
25+
assert.NoError(t, err)
26+
27+
chainID, err := l1Client.ChainID(ctx)
28+
assert.NoError(t, err)
29+
30+
opts, err := bind.NewKeyedTransactorWithChainID(sk, chainID)
31+
assert.NoError(t, err)
32+
opts.Context = ctx
33+
//opts.NoSend = true
34+
35+
balance, err := l1Client.BalanceAt(ctx, opts.From, nil)
36+
assert.NoError(t, err)
37+
t.Logf("address: %s, balance: %s", opts.From.String(), balance.String())
38+
39+
tx, err := l1Client.TransactBlobTx(opts, []byte("s"))
40+
assert.NoError(t, err)
41+
42+
receipt, err := bind.WaitMined(ctx, l1Client, tx)
43+
assert.NoError(t, err)
44+
t.Log(receipt)
45+
}

pkg/rpc/utils.go

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import (
1414
"github.com/ethereum/go-ethereum/core/txpool"
1515
"github.com/ethereum/go-ethereum/core/types"
1616
"github.com/ethereum/go-ethereum/log"
17+
"github.com/ethereum/go-ethereum/params"
18+
1719
"github.com/taikoxyz/taiko-client/bindings"
1820
"github.com/taikoxyz/taiko-client/bindings/encoding"
1921
"github.com/taikoxyz/taiko-client/internal/utils"
@@ -23,6 +25,7 @@ var (
2325
ZeroAddress common.Address
2426
waitReceiptPollingInterval = 3 * time.Second
2527
defaultWaitReceiptTimeout = 1 * time.Minute
28+
BlobBytes = params.BlobTxBytesPerFieldElement * params.BlobTxFieldElementsPerBlob
2629
)
2730

2831
// GetProtocolStateVariables gets the protocol states from TaikoL1 contract.

proposer/proposer.go

+32-4
Original file line numberDiff line numberDiff line change
@@ -307,10 +307,27 @@ func (p *Proposer) ProposeOp(ctx context.Context) error {
307307
return nil
308308
}
309309

310+
func (p *Proposer) sendTxListByBlobTx(ctx context.Context, txListBytes []byte) (*types.Transaction, error) {
311+
blobOpts, err := getTxOpts(ctx, p.rpc.L1, p.L1ProposerPrivKey, p.rpc.L1ChainID, nil)
312+
if err != nil {
313+
return nil, err
314+
}
315+
tx, err := p.rpc.L1.TransactBlobTx(blobOpts, txListBytes)
316+
if err != nil {
317+
return nil, err
318+
}
319+
// Wait until blob tx is mined.
320+
if _, err := bind.WaitMined(ctx, p.rpc.L1, tx); err != nil {
321+
return nil, err
322+
}
323+
324+
return tx, nil
325+
}
326+
310327
// sendProposeBlockTx tries to send a TaikoL1.proposeBlock transaction.
311328
func (p *Proposer) sendProposeBlockTx(
312329
ctx context.Context,
313-
txListBytes []byte,
330+
blobHash common.Hash,
314331
nonce *uint64,
315332
assignment *encoding.ProverAssignment,
316333
assignedProver common.Address,
@@ -376,7 +393,7 @@ func (p *Proposer) sendProposeBlockTx(
376393
ExtraData: rpc.StringToBytes32(p.ExtraData),
377394
TxListByteOffset: common.Big0,
378395
TxListByteSize: common.Big0,
379-
BlobHash: [32]byte{},
396+
BlobHash: blobHash,
380397
CacheBlobForReuse: false,
381398
ParentMetaHash: parentMetaHash,
382399
HookCalls: hookCalls,
@@ -388,8 +405,9 @@ func (p *Proposer) sendProposeBlockTx(
388405
proposeTx, err := p.rpc.TaikoL1.ProposeBlock(
389406
opts,
390407
encodedParams,
391-
txListBytes,
408+
nil,
392409
)
410+
393411
if err != nil {
394412
return nil, encoding.TryParsingCustomError(err)
395413
}
@@ -415,16 +433,26 @@ func (p *Proposer) ProposeTxList(
415433

416434
var (
417435
isReplacement bool
436+
blobTx *types.Transaction
418437
tx *types.Transaction
419438
)
420439
if err := backoff.Retry(
421440
func() error {
422441
if ctx.Err() != nil {
423442
return nil
424443
}
444+
445+
// Send tx list by blob tx.
446+
if blobTx == nil {
447+
blobTx, err = p.sendTxListByBlobTx(ctx, txListBytes)
448+
if err != nil {
449+
return nil
450+
}
451+
}
452+
425453
if tx, err = p.sendProposeBlockTx(
426454
ctx,
427-
txListBytes,
455+
blobTx.BlobHashes()[0],
428456
nonce,
429457
assignment,
430458
proverAddress,

0 commit comments

Comments
 (0)