@@ -3,23 +3,29 @@ package rpc
3
3
import (
4
4
"errors"
5
5
"fmt"
6
- "math/big"
7
6
8
- "github.com/ethereum/go-ethereum"
9
7
"github.com/ethereum/go-ethereum/accounts/abi/bind"
10
- "github.com/ethereum/go-ethereum/consensus/misc/eip4844"
8
+ "github.com/ethereum/go-ethereum/common"
9
+ "github.com/ethereum/go-ethereum/common/hexutil"
11
10
"github.com/ethereum/go-ethereum/core/types"
12
11
"github.com/ethereum/go-ethereum/crypto/kzg4844"
12
+ "github.com/ethereum/go-ethereum/params"
13
13
"github.com/holiman/uint256"
14
14
)
15
15
16
- func (c * EthClient ) TransactBlobTx (opts * bind.TransactOpts , data []byte ) (* types.Transaction , error ) {
16
+ // TransactBlobTx create, sign and send blob tx.
17
+ func (c * EthClient ) TransactBlobTx (
18
+ opts * bind.TransactOpts ,
19
+ contract * common.Address ,
20
+ input []byte ,
21
+ sidecar * types.BlobTxSidecar ,
22
+ ) (* types.Transaction , error ) {
17
23
// Sign the transaction and schedule it for execution
18
24
if opts .Signer == nil {
19
25
return nil , errors .New ("no signer to authorize the transaction with" )
20
26
}
21
27
// Create blob tx.
22
- rawTx , err := c .createBlobTx (opts , data )
28
+ rawTx , err := c .createBlobTx (opts , contract , input , sidecar )
23
29
if err != nil {
24
30
return nil , err
25
31
}
@@ -36,94 +42,76 @@ func (c *EthClient) TransactBlobTx(opts *bind.TransactOpts, data []byte) (*types
36
42
return signedTx , nil
37
43
}
38
44
39
- func (c * EthClient ) createBlobTx (opts * bind.TransactOpts , data []byte ) (* types.Transaction , error ) {
40
- header , err := c .HeaderByNumber (opts .Context , nil )
41
- if err != nil {
42
- return nil , err
45
+ func (c * EthClient ) createBlobTx (
46
+ opts * bind.TransactOpts ,
47
+ contract * common.Address ,
48
+ input []byte ,
49
+ sidecar * types.BlobTxSidecar ,
50
+ ) (* types.Transaction , error ) {
51
+ // Get nonce.
52
+ var nonce * hexutil.Uint64
53
+ if opts .Nonce != nil {
54
+ curNonce := hexutil .Uint64 (opts .Nonce .Uint64 ())
55
+ nonce = & curNonce
43
56
}
44
- // Estimate TipCap
45
- gasTipCap := opts .GasTipCap
46
- if gasTipCap == nil {
47
- tip , err := c .SuggestGasTipCap (opts .Context )
48
- if err != nil {
49
- return nil , err
50
- }
51
- gasTipCap = tip
52
- }
53
- // Estimate FeeCap
54
- gasFeeCap := opts .GasFeeCap
55
- if gasFeeCap == nil {
56
- gasFeeCap = new (big.Int ).Add (
57
- gasTipCap ,
58
- new (big.Int ).Mul (header .BaseFee , big .NewInt (2 )),
59
- )
60
- }
61
- if gasFeeCap .Cmp (gasTipCap ) < 0 {
62
- return nil , fmt .Errorf ("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)" , gasFeeCap , gasTipCap )
63
- }
64
- // Estimate GasLimit
65
- gasLimit := opts .GasLimit
66
- if opts .GasLimit == 0 {
67
- var err error
68
- gasLimit , err = c .EstimateGas (opts .Context , ethereum.CallMsg {
69
- From : opts .From ,
70
- To : nil ,
71
- GasPrice : nil ,
72
- GasTipCap : gasTipCap ,
73
- GasFeeCap : gasFeeCap ,
74
- Value : nil ,
75
- Data : nil ,
76
- })
77
- if err != nil {
78
- return nil , err
79
- }
57
+
58
+ if input == nil {
59
+ input = []byte {}
80
60
}
81
- // create the transaction
82
- nonce , err := c .getNonce (opts )
83
- if err != nil {
84
- return nil , err
61
+
62
+ if contract == nil {
63
+ contract = & common.Address {}
85
64
}
86
- chainID , err := c .ChainID (opts .Context )
87
- if err != nil {
88
- return nil , err
65
+
66
+ var gas * hexutil.Uint64
67
+ if opts .GasLimit != 0 {
68
+ var gasVal = hexutil .Uint64 (opts .GasLimit )
69
+ gas = & gasVal
89
70
}
90
71
91
- sidecar , err := makeSidecarWithSingleBlob (data )
72
+ rawTx , err := c .FillTransaction (opts .Context , & TransactionArgs {
73
+ From : & opts .From ,
74
+ To : contract ,
75
+ Gas : gas ,
76
+ GasPrice : (* hexutil .Big )(opts .GasPrice ),
77
+ MaxFeePerGas : (* hexutil .Big )(opts .GasFeeCap ),
78
+ MaxPriorityFeePerGas : (* hexutil .Big )(opts .GasTipCap ),
79
+ Value : (* hexutil .Big )(opts .Value ),
80
+ Nonce : nonce ,
81
+ Data : (* hexutil .Bytes )(& input ),
82
+ AccessList : nil ,
83
+ ChainID : nil ,
84
+ BlobFeeCap : nil ,
85
+ BlobHashes : sidecar .BlobHashes (),
86
+ })
92
87
if err != nil {
93
88
return nil , err
94
89
}
95
90
96
- var blobFeeCap uint64 = 100066
97
- if header .ExcessBlobGas != nil {
98
- blobFeeCap = * header .ExcessBlobGas
99
- }
100
-
101
- baseTx := & types.BlobTx {
102
- ChainID : uint256 .NewInt (chainID .Uint64 ()),
103
- Nonce : nonce ,
104
- GasTipCap : uint256 .NewInt (gasTipCap .Uint64 ()),
105
- GasFeeCap : uint256 .NewInt (gasFeeCap .Uint64 ()),
106
- Gas : gasLimit ,
107
- BlobFeeCap : uint256 .MustFromBig (eip4844 .CalcBlobFee (blobFeeCap )),
91
+ blobTx := & types.BlobTx {
92
+ ChainID : uint256 .MustFromBig (rawTx .ChainId ()),
93
+ Nonce : rawTx .Nonce (),
94
+ GasTipCap : uint256 .MustFromBig (rawTx .GasTipCap ()),
95
+ GasFeeCap : uint256 .MustFromBig (rawTx .GasFeeCap ()),
96
+ Gas : rawTx .Gas (),
97
+ To : * rawTx .To (),
98
+ Value : uint256 .MustFromBig (rawTx .Value ()),
99
+ Data : rawTx .Data (),
100
+ AccessList : rawTx .AccessList (),
101
+ BlobFeeCap : uint256 .MustFromBig (rawTx .BlobGasFeeCap ()),
108
102
BlobHashes : sidecar .BlobHashes (),
109
103
Sidecar : sidecar ,
110
104
}
111
- return types .NewTx (baseTx ), nil
112
- }
113
105
114
- func (c * EthClient ) getNonce (opts * bind.TransactOpts ) (uint64 , error ) {
115
- if opts .Nonce == nil {
116
- return c .PendingNonceAt (opts .Context , opts .From )
117
- }
118
- return opts .Nonce .Uint64 (), nil
106
+ return types .NewTx (blobTx ), nil
119
107
}
120
108
121
- func makeSidecarWithSingleBlob (data []byte ) (* types.BlobTxSidecar , error ) {
109
+ // MakeSidecarWithSingleBlob make a sidecar that just include one blob.
110
+ func MakeSidecarWithSingleBlob (data []byte ) (* types.BlobTxSidecar , error ) {
122
111
if len (data ) > BlobBytes {
123
112
return nil , fmt .Errorf ("data is bigger than 128k" )
124
113
}
125
- blob := kzg4844.Blob {}
126
- copy (blob [:], data )
114
+ blob := EncodeBlobs (data )[0 ]
127
115
commitment , err := kzg4844 .BlobToCommitment (blob )
128
116
if err != nil {
129
117
return nil , err
@@ -138,3 +126,49 @@ func makeSidecarWithSingleBlob(data []byte) (*types.BlobTxSidecar, error) {
138
126
Proofs : []kzg4844.Proof {proof },
139
127
}, nil
140
128
}
129
+
130
+ // EncodeBlobs encode bytes into Blob type.
131
+ func EncodeBlobs (data []byte ) []kzg4844.Blob {
132
+ blobs := []kzg4844.Blob {{}}
133
+ blobIndex := 0
134
+ fieldIndex := - 1
135
+ numOfElems := BlobBytes / 32
136
+ for i := 0 ; i < len (data ); i += 31 {
137
+ fieldIndex ++
138
+ if fieldIndex == numOfElems {
139
+ if blobIndex >= 1 {
140
+ break
141
+ }
142
+ blobs = append (blobs , kzg4844.Blob {})
143
+ blobIndex ++
144
+ fieldIndex = 0
145
+ }
146
+ max := i + 31
147
+ if max > len (data ) {
148
+ max = len (data )
149
+ }
150
+ copy (blobs [blobIndex ][fieldIndex * 32 + 1 :], data [i :max ])
151
+ }
152
+ return blobs
153
+ }
154
+
155
+ // DecodeBlob decode blob data.
156
+ func DecodeBlob (blob []byte ) []byte {
157
+ if len (blob ) != params .BlobTxFieldElementsPerBlob * 32 {
158
+ panic ("invalid blob encoding" )
159
+ }
160
+ var data []byte
161
+ for i , j := 0 , 0 ; i < params .BlobTxFieldElementsPerBlob ; i ++ {
162
+ data = append (data , blob [j :j + 31 ]... )
163
+ j += 32
164
+ }
165
+
166
+ i := len (data ) - 1
167
+ for ; i >= 0 ; i -- {
168
+ if data [i ] != 0x00 {
169
+ break
170
+ }
171
+ }
172
+ data = data [:i + 1 ]
173
+ return data
174
+ }
0 commit comments