[beta] Stricter uint256 RLP decoding. Update consensus tests to 10.1 (#3089)

* Clean up test runners. Don't run legacy tests

* Cherry pick https://github.com/ethereum/go-ethereum/pull/22927

* Tests update 10.1: Transaction Tests

* Port decodeBigInt changes to decodeUint256

* Introduce (*Stream) Uint256Bytes

* Temporarily disable stTransactionTest/HighGasPrice

* linter

* ttWrongRLP transaction tests pass now

* Fix stTransactionTest/HighGasPrice

Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
Andrew Ashikhmin 2021-12-06 08:00:54 +00:00 committed by GitHub
parent 3f34dee475
commit 759fb00593
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 191 additions and 286 deletions

View File

@ -203,12 +203,21 @@ func (st *StateTransition) to() common.Address {
func (st *StateTransition) buyGas(gasBailout bool) error { func (st *StateTransition) buyGas(gasBailout bool) error {
mgval := st.sharedBuyGas mgval := st.sharedBuyGas
mgval.SetUint64(st.msg.Gas()) mgval.SetUint64(st.msg.Gas())
mgval = mgval.Mul(mgval, st.gasPrice) mgval, overflow := mgval.MulOverflow(mgval, st.gasPrice)
if overflow {
return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex())
}
balanceCheck := mgval balanceCheck := mgval
if st.gasFeeCap != nil { if st.gasFeeCap != nil {
balanceCheck = st.sharedBuyGasBalance.SetUint64(st.msg.Gas()) balanceCheck = st.sharedBuyGasBalance.SetUint64(st.msg.Gas())
balanceCheck = balanceCheck.Mul(balanceCheck, st.gasFeeCap) balanceCheck, overflow = balanceCheck.MulOverflow(balanceCheck, st.gasFeeCap)
balanceCheck.Add(balanceCheck, st.value) if overflow {
return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex())
}
balanceCheck, overflow = balanceCheck.AddOverflow(balanceCheck, st.value)
if overflow {
return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex())
}
} }
if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 { if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 {
if !gasBailout { if !gasBailout {

View File

@ -465,22 +465,16 @@ func (tx *AccessListTx) DecodeRLP(s *rlp.Stream) error {
return err return err
} }
var b []byte var b []byte
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return fmt.Errorf("read ChainID: %w", err) return fmt.Errorf("read ChainID: %w", err)
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for ChainID: %d", len(b))
}
tx.ChainID = new(uint256.Int).SetBytes(b) tx.ChainID = new(uint256.Int).SetBytes(b)
if tx.Nonce, err = s.Uint(); err != nil { if tx.Nonce, err = s.Uint(); err != nil {
return fmt.Errorf("read Nonce: %w", err) return fmt.Errorf("read Nonce: %w", err)
} }
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return fmt.Errorf("read GasPrice: %w", err) return fmt.Errorf("read GasPrice: %w", err)
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for GasPrice: %d", len(b))
}
tx.GasPrice = new(uint256.Int).SetBytes(b) tx.GasPrice = new(uint256.Int).SetBytes(b)
if tx.Gas, err = s.Uint(); err != nil { if tx.Gas, err = s.Uint(); err != nil {
return fmt.Errorf("read Gas: %w", err) return fmt.Errorf("read Gas: %w", err)
@ -495,12 +489,9 @@ func (tx *AccessListTx) DecodeRLP(s *rlp.Stream) error {
tx.To = &common.Address{} tx.To = &common.Address{}
copy((*tx.To)[:], b) copy((*tx.To)[:], b)
} }
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return fmt.Errorf("read Value: %w", err) return fmt.Errorf("read Value: %w", err)
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for Value: %d", len(b))
}
tx.Value = new(uint256.Int).SetBytes(b) tx.Value = new(uint256.Int).SetBytes(b)
if tx.Data, err = s.Bytes(); err != nil { if tx.Data, err = s.Bytes(); err != nil {
return fmt.Errorf("read Data: %w", err) return fmt.Errorf("read Data: %w", err)
@ -511,26 +502,17 @@ func (tx *AccessListTx) DecodeRLP(s *rlp.Stream) error {
return fmt.Errorf("read AccessList: %w", err) return fmt.Errorf("read AccessList: %w", err)
} }
// decode V // decode V
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return fmt.Errorf("read V: %w", err) return fmt.Errorf("read V: %w", err)
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for V: %d", len(b))
}
tx.V.SetBytes(b) tx.V.SetBytes(b)
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return fmt.Errorf("read R: %w", err) return fmt.Errorf("read R: %w", err)
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for R: %d", len(b))
}
tx.R.SetBytes(b) tx.R.SetBytes(b)
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return fmt.Errorf("read S: %w", err) return fmt.Errorf("read S: %w", err)
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for S: %d", len(b))
}
tx.S.SetBytes(b) tx.S.SetBytes(b)
if err := s.ListEnd(); err != nil { if err := s.ListEnd(); err != nil {
return fmt.Errorf("close AccessListTx: %w", err) return fmt.Errorf("close AccessListTx: %w", err)

View File

@ -486,19 +486,13 @@ func (h *Header) DecodeRLP(s *rlp.Stream) error {
return fmt.Errorf("wrong size for Bloom: %d", len(b)) return fmt.Errorf("wrong size for Bloom: %d", len(b))
} }
copy(h.Bloom[:], b) copy(h.Bloom[:], b)
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return fmt.Errorf("read Difficulty: %w", err) return fmt.Errorf("read Difficulty: %w", err)
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for Difficulty: %d", len(b))
}
h.Difficulty = new(big.Int).SetBytes(b) h.Difficulty = new(big.Int).SetBytes(b)
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return fmt.Errorf("read Number: %w", err) return fmt.Errorf("read Number: %w", err)
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for Number: %d", len(b))
}
h.Number = new(big.Int).SetBytes(b) h.Number = new(big.Int).SetBytes(b)
if h.GasLimit, err = s.Uint(); err != nil { if h.GasLimit, err = s.Uint(); err != nil {
return fmt.Errorf("read GasLimit: %w", err) return fmt.Errorf("read GasLimit: %w", err)
@ -536,7 +530,7 @@ func (h *Header) DecodeRLP(s *rlp.Stream) error {
return fmt.Errorf("wrong size for Nonce: %d", len(b)) return fmt.Errorf("wrong size for Nonce: %d", len(b))
} }
copy(h.Nonce[:], b) copy(h.Nonce[:], b)
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
if errors.Is(err, rlp.EOL) { if errors.Is(err, rlp.EOL) {
h.BaseFee = nil h.BaseFee = nil
h.Eip1559 = false h.Eip1559 = false
@ -547,9 +541,6 @@ func (h *Header) DecodeRLP(s *rlp.Stream) error {
} }
return fmt.Errorf("read BaseFee: %w", err) return fmt.Errorf("read BaseFee: %w", err)
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for BaseFee: %d", len(b))
}
h.Eip1559 = true h.Eip1559 = true
h.BaseFee = new(big.Int).SetBytes(b) h.BaseFee = new(big.Int).SetBytes(b)
} }

View File

@ -378,29 +378,20 @@ func (tx *DynamicFeeTransaction) DecodeRLP(s *rlp.Stream) error {
return err return err
} }
var b []byte var b []byte
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return err return err
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for ChainID: %d", len(b))
}
tx.ChainID = new(uint256.Int).SetBytes(b) tx.ChainID = new(uint256.Int).SetBytes(b)
if tx.Nonce, err = s.Uint(); err != nil { if tx.Nonce, err = s.Uint(); err != nil {
return err return err
} }
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return err return err
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for MaxPriorityFeePerGas: %d", len(b))
}
tx.Tip = new(uint256.Int).SetBytes(b) tx.Tip = new(uint256.Int).SetBytes(b)
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return err return err
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for MaxFeePerGas: %d", len(b))
}
tx.FeeCap = new(uint256.Int).SetBytes(b) tx.FeeCap = new(uint256.Int).SetBytes(b)
if tx.Gas, err = s.Uint(); err != nil { if tx.Gas, err = s.Uint(); err != nil {
return err return err
@ -415,12 +406,9 @@ func (tx *DynamicFeeTransaction) DecodeRLP(s *rlp.Stream) error {
tx.To = &common.Address{} tx.To = &common.Address{}
copy((*tx.To)[:], b) copy((*tx.To)[:], b)
} }
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return err return err
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for Value: %d", len(b))
}
tx.Value = new(uint256.Int).SetBytes(b) tx.Value = new(uint256.Int).SetBytes(b)
if tx.Data, err = s.Bytes(); err != nil { if tx.Data, err = s.Bytes(); err != nil {
return err return err
@ -431,26 +419,17 @@ func (tx *DynamicFeeTransaction) DecodeRLP(s *rlp.Stream) error {
return err return err
} }
// decode V // decode V
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return err return err
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for V: %d", len(b))
}
tx.V.SetBytes(b) tx.V.SetBytes(b)
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return err return err
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for R: %d", len(b))
}
tx.R.SetBytes(b) tx.R.SetBytes(b)
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return err return err
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for S: %d", len(b))
}
tx.S.SetBytes(b) tx.S.SetBytes(b)
return s.ListEnd() return s.ListEnd()

View File

@ -369,12 +369,9 @@ func (tx *LegacyTx) DecodeRLP(s *rlp.Stream, encodingSize uint64) error {
return fmt.Errorf("read Nonce: %w", err) return fmt.Errorf("read Nonce: %w", err)
} }
var b []byte var b []byte
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return fmt.Errorf("read GasPrice: %w", err) return fmt.Errorf("read GasPrice: %w", err)
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for GasPrice: %d", len(b))
}
tx.GasPrice = new(uint256.Int).SetBytes(b) tx.GasPrice = new(uint256.Int).SetBytes(b)
if tx.Gas, err = s.Uint(); err != nil { if tx.Gas, err = s.Uint(); err != nil {
return fmt.Errorf("read Gas: %w", err) return fmt.Errorf("read Gas: %w", err)
@ -389,36 +386,24 @@ func (tx *LegacyTx) DecodeRLP(s *rlp.Stream, encodingSize uint64) error {
tx.To = &common.Address{} tx.To = &common.Address{}
copy((*tx.To)[:], b) copy((*tx.To)[:], b)
} }
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return fmt.Errorf("read Value: %w", err) return fmt.Errorf("read Value: %w", err)
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for Value: %d", len(b))
}
tx.Value = new(uint256.Int).SetBytes(b) tx.Value = new(uint256.Int).SetBytes(b)
if tx.Data, err = s.Bytes(); err != nil { if tx.Data, err = s.Bytes(); err != nil {
return fmt.Errorf("read Data: %w", err) return fmt.Errorf("read Data: %w", err)
} }
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return fmt.Errorf("read V: %w", err) return fmt.Errorf("read V: %w", err)
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for V: %d", len(b))
}
tx.V.SetBytes(b) tx.V.SetBytes(b)
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return fmt.Errorf("read R: %w", err) return fmt.Errorf("read R: %w", err)
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for R: %d", len(b))
}
tx.R.SetBytes(b) tx.R.SetBytes(b)
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return fmt.Errorf("read S: %w", err) return fmt.Errorf("read S: %w", err)
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for S: %d", len(b))
}
tx.S.SetBytes(b) tx.S.SetBytes(b)
if err = s.ListEnd(); err != nil { if err = s.ListEnd(); err != nil {
return fmt.Errorf("close tx struct: %w", err) return fmt.Errorf("close tx struct: %w", err)

View File

@ -373,12 +373,9 @@ func (nbp *NewBlockPacket) DecodeRLP(s *rlp.Stream) error {
} }
// decode TD // decode TD
var b []byte var b []byte
if b, err = s.Bytes(); err != nil { if b, err = s.Uint256Bytes(); err != nil {
return fmt.Errorf("read TD: %w", err) return fmt.Errorf("read TD: %w", err)
} }
if len(b) > 32 {
return fmt.Errorf("wrong size for TD: %d", len(b))
}
nbp.TD = new(big.Int).SetBytes(b) nbp.TD = new(big.Int).SetBytes(b)
if err = s.ListEnd(); err != nil { if err = s.ListEnd(); err != nil {
return err return err

View File

@ -242,19 +242,17 @@ func decodeBigIntNoPtr(s *Stream, val reflect.Value) error {
} }
func decodeBigInt(s *Stream, val reflect.Value) error { func decodeBigInt(s *Stream, val reflect.Value) error {
b, err := s.Bytes() b, err := s.bigIntBytes()
if err != nil { if err != nil {
return wrapStreamError(err, val.Type()) return wrapStreamError(err, val.Type())
} }
// Set the integer bytes.
i := val.Interface().(*big.Int) i := val.Interface().(*big.Int)
if i == nil { if i == nil {
i = new(big.Int) i = new(big.Int)
val.Set(reflect.ValueOf(i)) val.Set(reflect.ValueOf(i))
} }
// Reject leading zero bytes
if len(b) > 0 && b[0] == 0 {
return wrapStreamError(ErrCanonInt, val.Type())
}
i.SetBytes(b) i.SetBytes(b)
return nil return nil
} }
@ -264,22 +262,17 @@ func decodeUint256NoPtr(s *Stream, val reflect.Value) error {
} }
func decodeUint256(s *Stream, val reflect.Value) error { func decodeUint256(s *Stream, val reflect.Value) error {
b, err := s.Bytes() b, err := s.Uint256Bytes()
if err != nil { if err != nil {
return wrapStreamError(err, val.Type()) return wrapStreamError(err, val.Type())
} }
if len(b) > 32 {
return wrapStreamError(errUintOverflow, val.Type()) // Set the integer bytes.
}
i := val.Interface().(*uint256.Int) i := val.Interface().(*uint256.Int)
if i == nil { if i == nil {
i = new(uint256.Int) i = new(uint256.Int)
val.Set(reflect.ValueOf(i)) val.Set(reflect.ValueOf(i))
} }
// Reject leading zero bytes
if len(b) > 0 && b[0] == 0 {
return wrapStreamError(ErrCanonInt, val.Type())
}
i.SetBytes(b) i.SetBytes(b)
return nil return nil
} }
@ -599,7 +592,7 @@ type Stream struct {
limited bool limited bool
// auxiliary buffer for integer decoding // auxiliary buffer for integer decoding
uintbuf []byte uintbuf [32]byte
kind Kind // kind of value ahead kind Kind // kind of value ahead
size uint64 // size of value ahead size uint64 // size of value ahead
@ -734,6 +727,59 @@ func (s *Stream) uint(maxbits int) (uint64, error) {
} }
} }
func (s *Stream) Uint256Bytes() ([]byte, error) {
b, err := s.bigIntBytes()
if err != nil {
return nil, err
}
if len(b) > 32 {
return nil, errUintOverflow
}
return b, nil
}
func (s *Stream) bigIntBytes() ([]byte, error) {
var buffer []byte
kind, size, err := s.Kind()
switch {
case err != nil:
return nil, err
case kind == List:
return nil, 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)):
// For integers smaller than s.uintbuf, allocating a buffer
// can be avoided.
buffer = s.uintbuf[:size]
if err := s.readFull(buffer); err != nil {
return nil, err
}
// Reject inputs where single byte encoding should have been used.
if size == 1 && buffer[0] < 128 {
return nil, ErrCanonSize
}
default:
// For large integers, a temporary buffer is needed.
buffer = make([]byte, size)
if err := s.readFull(buffer); err != nil {
return nil, err
}
}
// Reject leading zero bytes.
if len(buffer) > 0 && buffer[0] == 0 {
return nil, ErrCanonInt
}
return buffer, nil
}
// Bool reads an RLP string of up to 1 byte and returns its contents // Bool reads an RLP string of up to 1 byte and returns its contents
// as a boolean. If the input does not contain an RLP string, the // as a boolean. If the input does not contain an RLP string, the
// returned error will be ErrExpectedString. // returned error will be ErrExpectedString.
@ -856,9 +902,7 @@ func (s *Stream) Reset(r io.Reader, inputLimit uint64) {
s.size = 0 s.size = 0
s.kind = -1 s.kind = -1
s.kinderr = nil s.kinderr = nil
if s.uintbuf == nil { s.uintbuf = [32]byte{}
s.uintbuf = make([]byte, 8)
}
s.byteval = 0 s.byteval = 0
} }
@ -977,20 +1021,20 @@ func (s *Stream) readUint(size byte) (uint64, error) {
b, err := s.readByte() b, err := s.readByte()
return uint64(b), err return uint64(b), err
default: default:
start := int(8 - size) buffer := s.uintbuf[:8]
for i := 0; i < start; i++ { for i := range buffer {
s.uintbuf[i] = 0 buffer[i] = 0
} }
if err := s.readFull(s.uintbuf[start:]); err != nil { start := int(8 - size)
if err := s.readFull(buffer[start:]); err != nil {
return 0, err return 0, err
} }
if s.uintbuf[start] == 0 { if buffer[start] == 0 {
// Note: readUint is also used to decode integer // Note: readUint is also used to decode integer values.
// values. The error needs to be adjusted to become // The error needs to be adjusted to become ErrCanonInt in this case.
// ErrCanonInt in this case.
return 0, ErrCanonSize return 0, ErrCanonSize
} }
return binary.BigEndian.Uint64(s.uintbuf), nil return binary.BigEndian.Uint64(buffer), nil
} }
} }

View File

@ -327,6 +327,11 @@ type recstruct struct {
Child *recstruct `rlp:"nil"` Child *recstruct `rlp:"nil"`
} }
type bigIntStruct struct {
I *big.Int
B string
}
type invalidNilTag struct { type invalidNilTag struct {
X []byte `rlp:"nil"` X []byte `rlp:"nil"`
} }
@ -375,6 +380,7 @@ var (
uint256.NewInt(0xFFFF), uint256.NewInt(0xFFFF),
) )
realBigInt = big.NewInt(0).SetBytes(unhex("010000000000000000000000000000000000000000000000000000000000000000")) realBigInt = big.NewInt(0).SetBytes(unhex("010000000000000000000000000000000000000000000000000000000000000000"))
veryVeryBigInt = new(big.Int).Exp(veryBigInt.ToBig(), big.NewInt(8), nil)
) )
type hasIgnoredField struct { type hasIgnoredField struct {
@ -451,13 +457,16 @@ var decodeTests = []decodeTest{
{input: "C0", ptr: new(string), error: "rlp: expected input string or byte for string"}, {input: "C0", ptr: new(string), error: "rlp: expected input string or byte for string"},
// big ints // big ints
{input: "80", ptr: new(*big.Int), value: big.NewInt(0)},
{input: "01", ptr: new(*big.Int), value: big.NewInt(1)}, {input: "01", ptr: new(*big.Int), value: big.NewInt(1)},
{input: "89FFFFFFFFFFFFFFFFFF", ptr: new(*big.Int), value: veryBigInt.ToBig()}, {input: "89FFFFFFFFFFFFFFFFFF", ptr: new(*big.Int), value: veryBigInt.ToBig()},
{input: "A1010000000000000000000000000000000000000000000000000000000000000000", ptr: new(*big.Int), value: realBigInt}, {input: "A1010000000000000000000000000000000000000000000000000000000000000000", ptr: new(*big.Int), value: realBigInt},
{input: "B848FFFFFFFFFFFFFFFFF800000000000000001BFFFFFFFFFFFFFFFFC8000000000000000045FFFFFFFFFFFFFFFFC800000000000000001BFFFFFFFFFFFFFFFFF8000000000000000001", ptr: new(*big.Int), value: veryVeryBigInt},
{input: "10", ptr: new(big.Int), value: *big.NewInt(16)}, // non-pointer also works {input: "10", ptr: new(big.Int), value: *big.NewInt(16)}, // non-pointer also works
{input: "C0", ptr: new(*big.Int), error: "rlp: expected input string or byte for *big.Int"}, {input: "C0", ptr: new(*big.Int), error: "rlp: expected input string or byte for *big.Int"},
{input: "820001", ptr: new(big.Int), error: "rlp: non-canonical integer (leading zero bytes) for *big.Int"}, {input: "00", ptr: new(*big.Int), error: "rlp: non-canonical integer (leading zero bytes) for *big.Int"},
{input: "8105", ptr: new(big.Int), error: "rlp: non-canonical size information for *big.Int"}, {input: "820001", ptr: new(*big.Int), error: "rlp: non-canonical integer (leading zero bytes) for *big.Int"},
{input: "8105", ptr: new(*big.Int), error: "rlp: non-canonical size information for *big.Int"},
// uint256 // uint256
{input: "01", ptr: new(*uint256.Int), value: uint256.NewInt(1)}, {input: "01", ptr: new(*uint256.Int), value: uint256.NewInt(1)},
@ -479,6 +488,13 @@ var decodeTests = []decodeTest{
ptr: new(recstruct), ptr: new(recstruct),
value: recstruct{1, &recstruct{2, &recstruct{3, nil}}}, value: recstruct{1, &recstruct{2, &recstruct{3, nil}}},
}, },
{
// This checks that empty big.Int works correctly in struct context. It's easy to
// miss the update of s.kind for this case, so it needs its own test.
input: "C58083343434",
ptr: new(bigIntStruct),
value: bigIntStruct{new(big.Int), "444"},
},
// struct errors // struct errors
{ {

View File

@ -134,6 +134,14 @@ var encTests = []encTest{
val: big.NewInt(0).SetBytes(unhex("010000000000000000000000000000000000000000000000000000000000000000")), val: big.NewInt(0).SetBytes(unhex("010000000000000000000000000000000000000000000000000000000000000000")),
output: "A1010000000000000000000000000000000000000000000000000000000000000000", output: "A1010000000000000000000000000000000000000000000000000000000000000000",
}, },
{
val: veryBigInt,
output: "89FFFFFFFFFFFFFFFFFF",
},
{
val: veryVeryBigInt,
output: "B848FFFFFFFFFFFFFFFFF800000000000000001BFFFFFFFFFFFFFFFFC8000000000000000045FFFFFFFFFFFFFFFFC800000000000000001BFFFFFFFFFFFFFFFFF8000000000000000001",
},
// non-pointer big.Int // non-pointer big.Int
{val: *big.NewInt(0), output: "80"}, {val: *big.NewInt(0), output: "80"},

View File

@ -32,33 +32,8 @@ func TestBlockchain(t *testing.T) {
bt := new(testMatcher) bt := new(testMatcher)
// General state tests are 'exported' as blockchain tests, but we can run them natively. // General state tests are 'exported' as blockchain tests, but we can run them natively.
// For speedier CI-runs, the line below can be uncommented, so those are skipped. // For speedier CI-runs those are skipped.
// For now, in hardfork-times (Berlin), we run the tests both as StateTests and bt.skipLoad(`^GeneralStateTests/`)
// as blockchain tests, since the latter also covers things like receipt root
//bt.skipLoad(`^GeneralStateTests/`)
// Skip random failures due to selfish mining test
bt.skipLoad(`.*bcForgedTest/bcForkUncle\.json`)
// Slow tests
bt.slow(`.*bcExploitTest/DelegateCallSpam.json`)
bt.slow(`.*bcExploitTest/ShanghaiLove.json`)
bt.slow(`.*bcExploitTest/SuicideIssue.json`)
bt.slow(`.*/bcForkStressTest/`)
bt.slow(`.*/bcGasPricerTest/RPC_API_Test.json`)
bt.slow(`.*/bcWalletTest/`)
// Very slow test
bt.skipLoad(`.*/stTimeConsuming/.*`)
// test takes a lot for time and goes easily OOM because of sha3 calculation on a huge range,
// using 4.6 TGas
bt.skipLoad(`.*randomStatetest94.json.*`)
bt.fails(`(?m)^TestBlockchain/InvalidBlocks/bcInvalidHeaderTest/wrongReceiptTrie.json/wrongReceiptTrie_EIP150`, "No receipt validation before Byzantium")
bt.fails(`(?m)^TestBlockchain/InvalidBlocks/bcInvalidHeaderTest/wrongReceiptTrie.json/wrongReceiptTrie_EIP158`, "No receipt validation before Byzantium")
bt.fails(`(?m)^TestBlockchain/InvalidBlocks/bcInvalidHeaderTest/wrongReceiptTrie.json/wrongReceiptTrie_Frontier`, "No receipt validation before Byzantium")
bt.fails(`(?m)^TestBlockchain/InvalidBlocks/bcInvalidHeaderTest/wrongReceiptTrie.json/wrongReceiptTrie_Homestead`, "No receipt validation before Byzantium")
bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) { bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) {
// import pre accounts & construct test genesis block & state root // import pre accounts & construct test genesis block & state root
@ -66,8 +41,4 @@ func TestBlockchain(t *testing.T) {
t.Error(err) t.Error(err)
} }
}) })
// There is also a LegacyTests folder, containing blockchain tests generated
// prior to Istanbul. However, they are all derived from GeneralStateTests,
// which run natively, so there's no reason to run them here.
} }

View File

@ -37,8 +37,6 @@ var (
baseDir = filepath.Join(".", "testdata") baseDir = filepath.Join(".", "testdata")
blockTestDir = filepath.Join(baseDir, "BlockchainTests") blockTestDir = filepath.Join(baseDir, "BlockchainTests")
stateTestDir = filepath.Join(baseDir, "GeneralStateTests") stateTestDir = filepath.Join(baseDir, "GeneralStateTests")
legacyStateTestDir = filepath.Join(baseDir, "LegacyTests", "Constantinople", "GeneralStateTests")
vmTestDir = filepath.Join(baseDir, "LegacyTests", "Constantinople", "VMTests")
transactionTestDir = filepath.Join(baseDir, "TransactionTests") transactionTestDir = filepath.Join(baseDir, "TransactionTests")
rlpTestDir = filepath.Join(baseDir, "RLPTests") rlpTestDir = filepath.Join(baseDir, "RLPTests")
difficultyTestDir = filepath.Join(baseDir, "BasicTests") difficultyTestDir = filepath.Join(baseDir, "BasicTests")

View File

@ -39,21 +39,10 @@ func TestState(t *testing.T) {
t.Parallel() t.Parallel()
st := new(testMatcher) st := new(testMatcher)
// Long tests:
st.slow(`^stAttackTest/ContractCreationSpam`)
st.slow(`^stBadOpcode/badOpcodes`)
st.slow(`^stPreCompiledContracts/modexp`)
st.slow(`^stQuadraticComplexityTest/`)
st.slow(`^stStaticCall/static_Call50000`)
st.slow(`^stStaticCall/static_Return50000`)
st.slow(`^stSystemOperationsTest/CallRecursiveBomb`)
st.slow(`^stTransactionTest/Opcodes_TransactionInit`)
// Very time consuming // Very time consuming
st.skipLoad(`^stTimeConsuming/`) st.skipLoad(`^stTimeConsuming/`)
st.skipLoad(`.*vmPerformance/loop.*`)
// Uses 1GB RAM per tested fork
st.skipLoad(`^stStaticCall/static_Call1MB`)
// Broken tests: // Broken tests:
st.skipLoad(`^stCreate2/create2collisionStorage.json`) st.skipLoad(`^stCreate2/create2collisionStorage.json`)
@ -61,20 +50,10 @@ func TestState(t *testing.T) {
st.skipLoad(`^stSStoreTest/InitCollision.json`) st.skipLoad(`^stSStoreTest/InitCollision.json`)
st.skipLoad(`^stEIP1559/typeTwoBerlin.json`) st.skipLoad(`^stEIP1559/typeTwoBerlin.json`)
// Expected failures: // https://github.com/ethereum/tests/issues/1001
//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/0`, "bug in test") st.skipLoad(`^stTransactionTest/ValueOverflow.json`)
//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/3`, "bug in test")
//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/0`, "bug in test")
//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/3`, "bug in test")
//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/0`, "bug in test")
//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/3`, "bug in test")
// For Istanbul, older tests were moved into LegacyTests st.walk(t, stateTestDir, func(t *testing.T, name string, test *StateTest) {
for _, dir := range []string{
stateTestDir,
legacyStateTestDir,
} {
st.walk(t, dir, func(t *testing.T, name string, test *StateTest) {
db := memdb.NewTestDB(t) db := memdb.NewTestDB(t)
for _, subtest := range test.Subtests() { for _, subtest := range test.Subtests() {
subtest := subtest subtest := subtest
@ -99,7 +78,6 @@ func TestState(t *testing.T) {
} }
}) })
} }
}
// Transactions with gasLimit above this value will not get a VM trace on failure. // Transactions with gasLimit above this value will not get a VM trace on failure.
const traceErrorLimit = 400000 const traceErrorLimit = 400000

View File

@ -230,13 +230,6 @@ func (t *StateTest) RunNoVerify(rules params.Rules, tx kv.RwTx, subtest StateSub
statedb.RevertToSnapshot(snapshot) statedb.RevertToSnapshot(snapshot)
} }
// And _now_ get the state root
// Add 0-value mining reward. This only makes a difference in the cases
// where
// - the coinbase suicided, or
// - there are only 'bad' transactions, which aren't executed. In those cases,
// the coinbase gets no txfee, so isn't created, and thus needs to be touched
statedb.AddBalance(block.Coinbase(), new(uint256.Int))
if err = statedb.FinalizeTx(evm.ChainRules, w); err != nil { if err = statedb.FinalizeTx(evm.ChainRules, w); err != nil {
return nil, common.Hash{}, err return nil, common.Hash{}, err
} }

@ -1 +1 @@
Subproject commit 52cb3b3e724d13943bd8a457ed70929f98b9b8bf Subproject commit fbff6fee061ade2358280a8d6f98f67b4ae2b60e

View File

@ -26,25 +26,16 @@ func TestTransaction(t *testing.T) {
t.Parallel() t.Parallel()
txt := new(testMatcher) txt := new(testMatcher)
// These can't be parsed, invalid hex in RLP
txt.skipLoad("^ttWrongRLP/.*")
// We don't allow more than uint64 in gas amount // We don't allow more than uint64 in gas amount
// This is a pseudo-consensus vulnerability, but not in practice // This is a pseudo-consensus vulnerability, but not in practice
// because of the gas limit // because of the gas limit
txt.skipLoad("^ttGasLimit/TransactionWithGasLimitxPriceOverflow.json") txt.skipLoad("^ttGasLimit/TransactionWithGasLimitxPriceOverflow.json")
// We _do_ allow more than uint64 in gas price, as opposed to the tests
// This is also not a concern, as long as tx.Cost() uses big.Int for
// calculating the final cozt
txt.skipLoad(".*TransactionWithGasPriceOverflow.*")
// The nonce is too large for uint64. Not a concern, it means geth won't // The nonce is too large for uint64. Not a concern, it means geth won't
// accept transactions at a certain point in the distant future // accept transactions at a certain point in the distant future
txt.skipLoad("^ttNonce/TransactionWithHighNonce256.json") txt.skipLoad("^ttNonce/TransactionWithHighNonce256.json")
// The value is larger than uint64, which according to the test is invalid.
// Geth accepts it, which is not a consensus issue since we use big.Int's
// internally to calculate the cost
txt.skipLoad("^ttValue/TransactionWithHighValueOverflow.json")
txt.walk(t, transactionTestDir, func(t *testing.T, name string, test *TransactionTest) { txt.walk(t, transactionTestDir, func(t *testing.T, name string, test *TransactionTest) {
cfg := params.MainnetChainConfig cfg := params.MainnetChainConfig
if err := txt.checkFailure(t, test.Run(cfg)); err != nil { if err := txt.checkFailure(t, test.Run(cfg)); err != nil {

View File

@ -30,19 +30,27 @@ import (
// TransactionTest checks RLP decoding and sender derivation of transactions. // TransactionTest checks RLP decoding and sender derivation of transactions.
type TransactionTest struct { type TransactionTest struct {
RLP hexutil.Bytes `json:"rlp"` RLP hexutil.Bytes `json:"txbytes"`
Forks ttForks `json:"result"`
}
type ttForks struct {
Berlin ttFork
Byzantium ttFork Byzantium ttFork
Constantinople ttFork Constantinople ttFork
Istanbul ttFork ConstantinopleFix ttFork
EIP150 ttFork EIP150 ttFork
EIP158 ttFork EIP158 ttFork
Frontier ttFork Frontier ttFork
Homestead ttFork Homestead ttFork
Istanbul ttFork
London ttFork
} }
type ttFork struct { type ttFork struct {
Sender common.UnprefixedAddress `json:"sender"` Exception string `json:"exception"`
Hash common.UnprefixedHash `json:"hash"` Sender common.Address `json:"sender"`
Hash common.Hash `json:"hash"`
} }
func (tt *TransactionTest) Run(config *params.ChainConfig) error { func (tt *TransactionTest) Run(config *params.ChainConfig) error {
@ -74,19 +82,22 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error {
isHomestead bool isHomestead bool
isIstanbul bool isIstanbul bool
}{ }{
{"Frontier", types.MakeFrontierSigner(), tt.Frontier, false, false}, {"Frontier", types.MakeFrontierSigner(), tt.Forks.Frontier, false, false},
{"Homestead", types.LatestSignerForChainID(nil), tt.Homestead, true, false}, {"Homestead", types.LatestSignerForChainID(nil), tt.Forks.Homestead, true, false},
{"EIP150", types.LatestSignerForChainID(nil), tt.EIP150, true, false}, {"EIP150", types.LatestSignerForChainID(nil), tt.Forks.EIP150, true, false},
{"EIP158", types.LatestSignerForChainID(config.ChainID), tt.EIP158, true, false}, {"EIP158", types.LatestSignerForChainID(config.ChainID), tt.Forks.EIP158, true, false},
{"Byzantium", types.LatestSignerForChainID(config.ChainID), tt.Byzantium, true, false}, {"Byzantium", types.LatestSignerForChainID(config.ChainID), tt.Forks.Byzantium, true, false},
{"Constantinople", types.LatestSignerForChainID(config.ChainID), tt.Constantinople, true, false}, {"Constantinople", types.LatestSignerForChainID(config.ChainID), tt.Forks.Constantinople, true, false},
{"Istanbul", types.LatestSignerForChainID(config.ChainID), tt.Istanbul, true, true}, {"ConstantinopleFix", types.LatestSignerForChainID(config.ChainID), tt.Forks.ConstantinopleFix, true, false},
{"Istanbul", types.LatestSignerForChainID(config.ChainID), tt.Forks.Istanbul, true, true},
{"Berlin", types.LatestSignerForChainID(config.ChainID), tt.Forks.Berlin, true, true},
{"London", types.LatestSignerForChainID(config.ChainID), tt.Forks.London, true, true},
} { } {
sender, txhash, err := validateTx(tt.RLP, *testcase.signer, testcase.isHomestead, testcase.isIstanbul) sender, txhash, err := validateTx(tt.RLP, *testcase.signer, testcase.isHomestead, testcase.isIstanbul)
if testcase.fork.Sender == (common.UnprefixedAddress{}) { if testcase.fork.Exception != "" {
if err == nil { if err == nil {
return fmt.Errorf("expected error, got none (address %v)[%v]", sender.String(), testcase.name) return fmt.Errorf("expected error %v, got none [%v]", testcase.fork.Exception, testcase.name)
} }
continue continue
} }

View File

@ -1,48 +0,0 @@
// Copyright 2014 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 tests
import (
"context"
"testing"
"github.com/ledgerwatch/erigon-lib/kv/memdb"
"github.com/ledgerwatch/erigon/core/vm"
"github.com/ledgerwatch/log/v3"
)
func TestVM(t *testing.T) {
defer log.Root().SetHandler(log.Root().GetHandler())
log.Root().SetHandler(log.LvlFilterHandler(log.LvlError, log.StderrHandler))
t.Parallel()
vmt := new(testMatcher)
vmt.slow("^vmPerformance")
vmt.fails("^vmSystemOperationsTest.json/createNameRegistrator$", "fails without parallel execution")
db := memdb.NewTestDB(t)
vmt.walk(t, vmTestDir, func(t *testing.T, name string, test *VMTest) {
withTrace(t, test.json.Exec.GasLimit, func(vmconfig vm.Config) error {
tx, err := db.BeginRw(context.Background())
if err != nil {
t.Fatal(err)
}
defer tx.Rollback()
return vmt.checkFailure(t, test.Run(tx, vmconfig, 0))
})
})
}