mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-23 13:16:42 +00:00
feat(ethclient & gethclient): support blob transaction (#661)
* feat: support blob transaction * sync tx encoding/decoding * more fixes * add uint236 support in rlp encoding decoding * revert a format change * trigger ci
This commit is contained in:
parent
ccec84ce63
commit
4553f5f269
14 changed files with 284 additions and 20 deletions
60
consensus/misc/eip4844.go
Normal file
60
consensus/misc/eip4844.go
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright 2023 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package misc
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/params"
|
||||
)
|
||||
|
||||
var (
|
||||
minBlobGasPrice = big.NewInt(params.BlobTxMinBlobGasprice)
|
||||
blobGaspriceUpdateFraction = big.NewInt(params.BlobTxBlobGaspriceUpdateFraction)
|
||||
)
|
||||
|
||||
// CalcExcessBlobGas calculates the excess blob gas after applying the set of
|
||||
// blobs on top of the excess blob gas.
|
||||
func CalcExcessBlobGas(parentExcessBlobGas uint64, parentBlobGasUsed uint64) uint64 {
|
||||
excessBlobGas := parentExcessBlobGas + parentBlobGasUsed
|
||||
if excessBlobGas < params.BlobTxTargetBlobGasPerBlock {
|
||||
return 0
|
||||
}
|
||||
return excessBlobGas - params.BlobTxTargetBlobGasPerBlock
|
||||
}
|
||||
|
||||
// CalcBlobFee calculates the blobfee from the header's excess blob gas field.
|
||||
func CalcBlobFee(excessBlobGas uint64) *big.Int {
|
||||
return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(excessBlobGas), blobGaspriceUpdateFraction)
|
||||
}
|
||||
|
||||
// fakeExponential approximates factor * e ** (numerator / denominator) using
|
||||
// Taylor expansion.
|
||||
func fakeExponential(factor, numerator, denominator *big.Int) *big.Int {
|
||||
var (
|
||||
output = new(big.Int)
|
||||
accum = new(big.Int).Mul(factor, denominator)
|
||||
)
|
||||
for i := 1; accum.Sign() > 0; i++ {
|
||||
output.Add(output, accum)
|
||||
|
||||
accum.Mul(accum, numerator)
|
||||
accum.Div(accum, denominator)
|
||||
accum.Div(accum, big.NewInt(int64(i)))
|
||||
}
|
||||
return output.Div(output, denominator)
|
||||
}
|
||||
|
|
@ -17,9 +17,11 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/big"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
//go:generate gencodec -type AccessTuple -out gen_access_tuple.go
|
||||
|
|
@ -113,3 +115,11 @@ func (tx *AccessListTx) rawSignatureValues() (v, r, s *big.Int) {
|
|||
func (tx *AccessListTx) setSignatureValues(chainID, v, r, s *big.Int) {
|
||||
tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s
|
||||
}
|
||||
|
||||
func (tx *AccessListTx) encode(b *bytes.Buffer) error {
|
||||
return rlp.Encode(b, tx)
|
||||
}
|
||||
|
||||
func (tx *AccessListTx) decode(input []byte) error {
|
||||
return rlp.DecodeBytes(input, tx)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,11 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/big"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
type DynamicFeeTx struct {
|
||||
|
|
@ -101,3 +103,11 @@ func (tx *DynamicFeeTx) rawSignatureValues() (v, r, s *big.Int) {
|
|||
func (tx *DynamicFeeTx) setSignatureValues(chainID, v, r, s *big.Int) {
|
||||
tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s
|
||||
}
|
||||
|
||||
func (tx *DynamicFeeTx) encode(b *bytes.Buffer) error {
|
||||
return rlp.Encode(b, tx)
|
||||
}
|
||||
|
||||
func (tx *DynamicFeeTx) decode(input []byte) error {
|
||||
return rlp.DecodeBytes(input, tx)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/big"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
// payload, RLP encoded
|
||||
|
|
@ -52,3 +54,11 @@ func (tx *L1MessageTx) rawSignatureValues() (v, r, s *big.Int) {
|
|||
func (tx *L1MessageTx) setSignatureValues(chainID, v, r, s *big.Int) {
|
||||
// this is a noop for l1 message transactions
|
||||
}
|
||||
|
||||
func (tx *L1MessageTx) encode(b *bytes.Buffer) error {
|
||||
return rlp.Encode(b, tx)
|
||||
}
|
||||
|
||||
func (tx *L1MessageTx) decode(input []byte) error {
|
||||
return rlp.DecodeBytes(input, tx)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/big"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
|
|
@ -110,3 +111,11 @@ func (tx *LegacyTx) rawSignatureValues() (v, r, s *big.Int) {
|
|||
func (tx *LegacyTx) setSignatureValues(chainID, v, r, s *big.Int) {
|
||||
tx.V, tx.R, tx.S = v, r, s
|
||||
}
|
||||
|
||||
func (tx *LegacyTx) encode(*bytes.Buffer) error {
|
||||
panic("encode called on LegacyTx")
|
||||
}
|
||||
|
||||
func (tx *LegacyTx) decode([]byte) error {
|
||||
panic("decode called on LegacyTx)")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ var (
|
|||
ErrTxTypeNotSupported = errors.New("transaction type not supported")
|
||||
ErrGasFeeCapTooLow = errors.New("fee cap less than base fee")
|
||||
errEmptyTypedTx = errors.New("empty typed transaction bytes")
|
||||
errShortTypedTx = errors.New("typed transaction too short")
|
||||
errInvalidYParity = errors.New("'yParity' field must be 0 or 1")
|
||||
errVYParityMismatch = errors.New("'v' and 'yParity' fields do not match")
|
||||
errVYParityMissing = errors.New("missing 'yParity' or 'v' field in transaction")
|
||||
|
|
@ -94,6 +95,9 @@ type TxData interface {
|
|||
|
||||
rawSignatureValues() (v, r, s *big.Int)
|
||||
setSignatureValues(chainID, v, r, s *big.Int)
|
||||
|
||||
encode(*bytes.Buffer) error
|
||||
decode([]byte) error
|
||||
}
|
||||
|
||||
// EncodeRLP implements rlp.Encoder
|
||||
|
|
@ -114,7 +118,7 @@ func (tx *Transaction) EncodeRLP(w io.Writer) error {
|
|||
// encodeTyped writes the canonical encoding of a typed transaction to w.
|
||||
func (tx *Transaction) encodeTyped(w *bytes.Buffer) error {
|
||||
w.WriteByte(tx.Type())
|
||||
return rlp.Encode(w, tx.inner)
|
||||
return tx.inner.encode(w)
|
||||
}
|
||||
|
||||
// MarshalBinary returns the canonical encoding of the transaction.
|
||||
|
|
@ -143,7 +147,9 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
|
|||
tx.setDecoded(&inner, int(rlp.ListSize(size)))
|
||||
}
|
||||
return err
|
||||
case kind == rlp.String:
|
||||
case kind == rlp.Byte:
|
||||
return errShortTypedTx
|
||||
default:
|
||||
// It's an EIP-2718 typed TX envelope.
|
||||
var b []byte
|
||||
if b, err = s.Bytes(); err != nil {
|
||||
|
|
@ -154,8 +160,6 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
|
|||
tx.setDecoded(inner, len(b))
|
||||
}
|
||||
return err
|
||||
default:
|
||||
return rlp.ErrExpectedList
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -183,29 +187,24 @@ func (tx *Transaction) UnmarshalBinary(b []byte) error {
|
|||
|
||||
// decodeTyped decodes a typed transaction from the canonical format.
|
||||
func (tx *Transaction) decodeTyped(b []byte) (TxData, error) {
|
||||
if len(b) == 0 {
|
||||
return nil, errEmptyTypedTx
|
||||
if len(b) <= 1 {
|
||||
return nil, errShortTypedTx
|
||||
}
|
||||
var inner TxData
|
||||
switch b[0] {
|
||||
case AccessListTxType:
|
||||
var inner AccessListTx
|
||||
err := rlp.DecodeBytes(b[1:], &inner)
|
||||
return &inner, err
|
||||
inner = new(AccessListTx)
|
||||
case DynamicFeeTxType:
|
||||
var inner DynamicFeeTx
|
||||
err := rlp.DecodeBytes(b[1:], &inner)
|
||||
return &inner, err
|
||||
inner = new(DynamicFeeTx)
|
||||
case BlobTxType:
|
||||
var inner BlobTx
|
||||
err := rlp.DecodeBytes(b[1:], &inner)
|
||||
return &inner, err
|
||||
inner = new(BlobTx)
|
||||
case L1MessageTxType:
|
||||
var inner L1MessageTx
|
||||
err := rlp.DecodeBytes(b[1:], &inner)
|
||||
return &inner, err
|
||||
inner = new(L1MessageTx)
|
||||
default:
|
||||
return nil, ErrTxTypeNotSupported
|
||||
}
|
||||
err := inner.decode(b[1:])
|
||||
return inner, err
|
||||
}
|
||||
|
||||
// setDecoded sets the inner transaction and size after decoding.
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||
"github.com/scroll-tech/go-ethereum/crypto/kzg4844"
|
||||
)
|
||||
|
||||
// txJSON is the JSON representation of transactions.
|
||||
|
|
@ -48,6 +49,11 @@ type txJSON struct {
|
|||
S *hexutil.Big `json:"s"`
|
||||
YParity *hexutil.Uint64 `json:"yParity,omitempty"`
|
||||
|
||||
// Blob transaction sidecar encoding:
|
||||
Blobs []kzg4844.Blob `json:"blobs,omitempty"`
|
||||
Commitments []kzg4844.Commitment `json:"commitments,omitempty"`
|
||||
Proofs []kzg4844.Proof `json:"proofs,omitempty"`
|
||||
|
||||
// Only used for encoding:
|
||||
Hash common.Hash `json:"hash"`
|
||||
|
||||
|
|
@ -155,6 +161,11 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) {
|
|||
enc.S = (*hexutil.Big)(itx.S.ToBig())
|
||||
yparity := itx.V.Uint64()
|
||||
enc.YParity = (*hexutil.Uint64)(&yparity)
|
||||
if sidecar := itx.Sidecar; sidecar != nil {
|
||||
enc.Blobs = itx.Sidecar.Blobs
|
||||
enc.Commitments = itx.Sidecar.Commitments
|
||||
enc.Proofs = itx.Sidecar.Proofs
|
||||
}
|
||||
}
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -719,5 +719,20 @@ func toCallArg(msg ethereum.CallMsg) interface{} {
|
|||
if msg.GasPrice != nil {
|
||||
arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
|
||||
}
|
||||
if msg.GasFeeCap != nil {
|
||||
arg["maxFeePerGas"] = (*hexutil.Big)(msg.GasFeeCap)
|
||||
}
|
||||
if msg.GasTipCap != nil {
|
||||
arg["maxPriorityFeePerGas"] = (*hexutil.Big)(msg.GasTipCap)
|
||||
}
|
||||
if msg.AccessList != nil {
|
||||
arg["accessList"] = msg.AccessList
|
||||
}
|
||||
if msg.BlobGasFeeCap != nil {
|
||||
arg["maxFeePerBlobGas"] = (*hexutil.Big)(msg.BlobGasFeeCap)
|
||||
}
|
||||
if msg.BlobHashes != nil {
|
||||
arg["blobVersionedHashes"] = msg.BlobHashes
|
||||
}
|
||||
return arg
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,6 +213,21 @@ func toCallArg(msg ethereum.CallMsg) interface{} {
|
|||
if msg.GasPrice != nil {
|
||||
arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
|
||||
}
|
||||
if msg.GasFeeCap != nil {
|
||||
arg["maxFeePerGas"] = (*hexutil.Big)(msg.GasFeeCap)
|
||||
}
|
||||
if msg.GasTipCap != nil {
|
||||
arg["maxPriorityFeePerGas"] = (*hexutil.Big)(msg.GasTipCap)
|
||||
}
|
||||
if msg.AccessList != nil {
|
||||
arg["accessList"] = msg.AccessList
|
||||
}
|
||||
if msg.BlobGasFeeCap != nil {
|
||||
arg["maxFeePerBlobGas"] = (*hexutil.Big)(msg.BlobGasFeeCap)
|
||||
}
|
||||
if msg.BlobHashes != nil {
|
||||
arg["blobVersionedHashes"] = msg.BlobHashes
|
||||
}
|
||||
return arg
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -123,6 +123,10 @@ type CallMsg struct {
|
|||
Data []byte // input data, usually an ABI-encoded contract method invocation
|
||||
|
||||
AccessList types.AccessList // EIP-2930 access list.
|
||||
|
||||
// For BlobTxType
|
||||
BlobGasFeeCap *big.Int
|
||||
BlobHashes []common.Hash
|
||||
}
|
||||
|
||||
// A ContractCaller provides contract calls, essentially transactions that are executed by
|
||||
|
|
|
|||
|
|
@ -160,7 +160,11 @@ const (
|
|||
RefundQuotient uint64 = 2
|
||||
RefundQuotientEIP3529 uint64 = 5
|
||||
|
||||
BlobTxBlobGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size)
|
||||
BlobTxBlobGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size)
|
||||
BlobTxMinBlobGasprice = 1 // Minimum gas price for data blobs
|
||||
BlobTxBlobGaspriceUpdateFraction = 3338477 // Controls the maximum rate of change for blob gas price
|
||||
|
||||
BlobTxTargetBlobGasPerBlock = 3 * BlobTxBlobGasPerBlob // Target consumable blob gas for data blobs per block (for 1559-like pricing)
|
||||
)
|
||||
|
||||
// Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import (
|
|||
const (
|
||||
VersionMajor = 5 // Major version component of the current release
|
||||
VersionMinor = 1 // Minor version component of the current release
|
||||
VersionPatch = 22 // Patch version component of the current release
|
||||
VersionPatch = 23 // Patch version component of the current release
|
||||
VersionMeta = "mainnet" // Version metadata to append to the version string
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
//lint:ignore ST1012 EOL is not an error.
|
||||
|
|
@ -50,6 +52,7 @@ var (
|
|||
errUintOverflow = errors.New("rlp: uint overflow")
|
||||
errNoPointer = errors.New("rlp: interface given to Decode must be a pointer")
|
||||
errDecodeIntoNil = errors.New("rlp: pointer given to Decode must not be nil")
|
||||
errUint256Large = errors.New("rlp: value too large for uint256")
|
||||
|
||||
streamPool = sync.Pool{
|
||||
New: func() interface{} { return new(Stream) },
|
||||
|
|
@ -146,6 +149,7 @@ func addErrorContext(err error, ctx string) error {
|
|||
var (
|
||||
decoderInterface = reflect.TypeOf(new(Decoder)).Elem()
|
||||
bigInt = reflect.TypeOf(big.Int{})
|
||||
u256Int = reflect.TypeOf(uint256.Int{})
|
||||
)
|
||||
|
||||
func makeDecoder(typ reflect.Type, tags tags) (dec decoder, err error) {
|
||||
|
|
@ -157,6 +161,10 @@ func makeDecoder(typ reflect.Type, tags tags) (dec decoder, err error) {
|
|||
return decodeBigInt, nil
|
||||
case typ.AssignableTo(bigInt):
|
||||
return decodeBigIntNoPtr, nil
|
||||
case typ == reflect.PtrTo(u256Int):
|
||||
return decodeU256, nil
|
||||
case typ == u256Int:
|
||||
return decodeU256NoPtr, nil
|
||||
case kind == reflect.Ptr:
|
||||
return makePtrDecoder(typ, tags)
|
||||
case reflect.PtrTo(typ).Implements(decoderInterface):
|
||||
|
|
@ -268,6 +276,24 @@ func decodeBigInt(s *Stream, val reflect.Value) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func decodeU256NoPtr(s *Stream, val reflect.Value) error {
|
||||
return decodeU256(s, val.Addr())
|
||||
}
|
||||
|
||||
func decodeU256(s *Stream, val reflect.Value) error {
|
||||
i := val.Interface().(*uint256.Int)
|
||||
if i == nil {
|
||||
i = new(uint256.Int)
|
||||
val.Set(reflect.ValueOf(i))
|
||||
}
|
||||
|
||||
err := s.ReadUint256(i)
|
||||
if err != nil {
|
||||
return wrapStreamError(err, val.Type())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeListDecoder(typ reflect.Type, tag tags) (decoder, error) {
|
||||
etype := typ.Elem()
|
||||
if etype.Kind() == reflect.Uint8 && !reflect.PtrTo(etype).Implements(decoderInterface) {
|
||||
|
|
@ -781,6 +807,45 @@ func (s *Stream) ListEnd() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ReadUint256 decodes the next value as a uint256.
|
||||
func (s *Stream) ReadUint256(dst *uint256.Int) error {
|
||||
var buffer []byte
|
||||
kind, size, err := s.Kind()
|
||||
switch {
|
||||
case err != nil:
|
||||
return err
|
||||
case kind == List:
|
||||
return ErrExpectedString
|
||||
case kind == Byte:
|
||||
buffer = s.uintbuf[:1]
|
||||
buffer[0] = s.byteval
|
||||
s.kind = -1 // re-arm Kind
|
||||
case size == 0:
|
||||
// Avoid zero-length read.
|
||||
s.kind = -1
|
||||
case size <= uint64(len(s.uintbuf)):
|
||||
// All possible uint256 values fit into s.uintbuf.
|
||||
buffer = s.uintbuf[:size]
|
||||
if err := s.readFull(buffer); err != nil {
|
||||
return err
|
||||
}
|
||||
// Reject inputs where single byte encoding should have been used.
|
||||
if size == 1 && buffer[0] < 128 {
|
||||
return ErrCanonSize
|
||||
}
|
||||
default:
|
||||
return errUint256Large
|
||||
}
|
||||
|
||||
// Reject leading zero bytes.
|
||||
if len(buffer) > 0 && buffer[0] == 0 {
|
||||
return ErrCanonInt
|
||||
}
|
||||
// Set the integer bytes.
|
||||
dst.SetBytes(buffer)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode decodes a value and stores the result in the value pointed
|
||||
// to by val. Please see the documentation for the Decode function
|
||||
// to learn about the decoding rules.
|
||||
|
|
|
|||
|
|
@ -17,11 +17,14 @@
|
|||
package rlp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -189,6 +192,35 @@ func (w *encbuf) encodeUint(i uint64) {
|
|||
}
|
||||
}
|
||||
|
||||
func (w *encbuf) writeUint64(i uint64) {
|
||||
if i == 0 {
|
||||
w.str = append(w.str, 0x80)
|
||||
} else if i < 128 {
|
||||
// fits single byte
|
||||
w.str = append(w.str, byte(i))
|
||||
} else {
|
||||
s := putint(w.sizebuf[1:], i)
|
||||
w.sizebuf[0] = 0x80 + byte(s)
|
||||
w.str = append(w.str, w.sizebuf[:s+1]...)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *encbuf) writeUint256(z *uint256.Int) {
|
||||
bitlen := z.BitLen()
|
||||
if bitlen <= 64 {
|
||||
w.writeUint64(z.Uint64())
|
||||
return
|
||||
}
|
||||
nBytes := byte((bitlen + 7) / 8)
|
||||
var b [33]byte
|
||||
binary.BigEndian.PutUint64(b[1:9], z[3])
|
||||
binary.BigEndian.PutUint64(b[9:17], z[2])
|
||||
binary.BigEndian.PutUint64(b[17:25], z[1])
|
||||
binary.BigEndian.PutUint64(b[25:33], z[0])
|
||||
b[32-nBytes] = 0x80 + nBytes
|
||||
w.str = append(w.str, b[32-nBytes:]...)
|
||||
}
|
||||
|
||||
// list adds a new list header to the header stack. It returns the index
|
||||
// of the header. The caller must call listEnd with this index after encoding
|
||||
// the content of the list.
|
||||
|
|
@ -332,6 +364,10 @@ func makeWriter(typ reflect.Type, ts tags) (writer, error) {
|
|||
return writeBigIntPtr, nil
|
||||
case typ.AssignableTo(bigInt):
|
||||
return writeBigIntNoPtr, nil
|
||||
case typ == reflect.PtrTo(u256Int):
|
||||
return writeU256IntPtr, nil
|
||||
case typ == u256Int:
|
||||
return writeU256IntNoPtr, nil
|
||||
case kind == reflect.Ptr:
|
||||
return makePtrWriter(typ, ts)
|
||||
case reflect.PtrTo(typ).Implements(encoderInterface):
|
||||
|
|
@ -420,6 +456,22 @@ func writeBigInt(i *big.Int, w *encbuf) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func writeU256IntPtr(val reflect.Value, w *encbuf) error {
|
||||
ptr := val.Interface().(*uint256.Int)
|
||||
if ptr == nil {
|
||||
w.str = append(w.str, 0x80)
|
||||
return nil
|
||||
}
|
||||
w.writeUint256(ptr)
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeU256IntNoPtr(val reflect.Value, w *encbuf) error {
|
||||
i := val.Interface().(uint256.Int)
|
||||
w.writeUint256(&i)
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeBytes(val reflect.Value, w *encbuf) error {
|
||||
w.encodeString(val.Bytes())
|
||||
return nil
|
||||
|
|
|
|||
Loading…
Reference in a new issue