aboutsummaryrefslogtreecommitdiff
path: root/core/vm
diff options
context:
space:
mode:
Diffstat (limited to 'core/vm')
-rw-r--r--core/vm/common.go31
-rw-r--r--core/vm/contract.go36
-rw-r--r--core/vm/contracts.go487
-rw-r--r--core/vm/eips.go82
-rw-r--r--core/vm/errors.go49
-rw-r--r--core/vm/evm.go281
-rw-r--r--core/vm/gas.go10
-rw-r--r--core/vm/gas_table.go76
-rw-r--r--core/vm/gen_structlog.go26
-rw-r--r--core/vm/instructions.go979
-rw-r--r--core/vm/int_pool_verifier.go31
-rw-r--r--core/vm/int_pool_verifier_empty.go23
-rw-r--r--core/vm/interface.go2
-rw-r--r--core/vm/interpreter.go94
-rw-r--r--core/vm/intpool.go106
-rw-r--r--core/vm/jump_table.go181
-rw-r--r--core/vm/logger.go189
-rw-r--r--core/vm/logger_json.go19
-rw-r--r--core/vm/memory.go9
-rw-r--r--core/vm/opcodes.go62
-rw-r--r--core/vm/stack.go84
21 files changed, 1652 insertions, 1205 deletions
diff --git a/core/vm/common.go b/core/vm/common.go
index ead30fc..90ba4a4 100644
--- a/core/vm/common.go
+++ b/core/vm/common.go
@@ -17,15 +17,14 @@
package vm
import (
- "math/big"
-
- "github.com/ava-labs/go-ethereum/common"
- "github.com/ava-labs/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
+ "github.com/holiman/uint256"
)
// calcMemSize64 calculates the required memory size, and returns
// the size and whether the result overflowed uint64
-func calcMemSize64(off, l *big.Int) (uint64, bool) {
+func calcMemSize64(off, l *uint256.Int) (uint64, bool) {
if !l.IsUint64() {
return 0, true
}
@@ -35,16 +34,16 @@ func calcMemSize64(off, l *big.Int) (uint64, bool) {
// calcMemSize64WithUint calculates the required memory size, and returns
// the size and whether the result overflowed uint64
// Identical to calcMemSize64, but length is a uint64
-func calcMemSize64WithUint(off *big.Int, length64 uint64) (uint64, bool) {
+func calcMemSize64WithUint(off *uint256.Int, length64 uint64) (uint64, bool) {
// if length is zero, memsize is always zero, regardless of offset
if length64 == 0 {
return 0, false
}
// Check that offset doesn't overflow
- if !off.IsUint64() {
+ offset64, overflow := off.Uint64WithOverflow()
+ if overflow {
return 0, true
}
- offset64 := off.Uint64()
val := offset64 + length64
// if value < either of it's parts, then it overflowed
return val, val < offset64
@@ -64,22 +63,6 @@ func getData(data []byte, start uint64, size uint64) []byte {
return common.RightPadBytes(data[start:end], int(size))
}
-// getDataBig returns a slice from the data based on the start and size and pads
-// up to size with zero's. This function is overflow safe.
-func getDataBig(data []byte, start *big.Int, size *big.Int) []byte {
- dlen := big.NewInt(int64(len(data)))
-
- s := math.BigMin(start, dlen)
- e := math.BigMin(new(big.Int).Add(s, size), dlen)
- return common.RightPadBytes(data[s.Uint64():e.Uint64()], int(size.Uint64()))
-}
-
-// bigUint64 returns the integer casted to a uint64 and returns whether it
-// overflowed in the process.
-func bigUint64(v *big.Int) (uint64, bool) {
- return v.Uint64(), !v.IsUint64()
-}
-
// toWordSize returns the ceiled word size required for memory expansion.
func toWordSize(size uint64) uint64 {
if size > math.MaxUint64-31 {
diff --git a/core/vm/contract.go b/core/vm/contract.go
index ed17402..915193d 100644
--- a/core/vm/contract.go
+++ b/core/vm/contract.go
@@ -19,7 +19,8 @@ package vm
import (
"math/big"
- "github.com/ava-labs/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/holiman/uint256"
)
// ContractRef is a reference to the contract's backing object
@@ -81,18 +82,43 @@ func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uin
return c
}
-func (c *Contract) validJumpdest(dest *big.Int) bool {
- udest := dest.Uint64()
+func (c *Contract) validJumpdest(dest *uint256.Int) bool {
+ udest, overflow := dest.Uint64WithOverflow()
// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
// Don't bother checking for JUMPDEST in that case.
- if dest.BitLen() >= 63 || udest >= uint64(len(c.Code)) {
+ if overflow || udest >= uint64(len(c.Code)) {
return false
}
// Only JUMPDESTs allowed for destinations
if OpCode(c.Code[udest]) != JUMPDEST {
return false
}
+ return c.isCode(udest)
+}
+
+func (c *Contract) validJumpSubdest(udest uint64) bool {
+ // PC cannot go beyond len(code) and certainly can't be bigger than 63 bits.
+ // Don't bother checking for BEGINSUB in that case.
+ if int64(udest) < 0 || udest >= uint64(len(c.Code)) {
+ return false
+ }
+ // Only BEGINSUBs allowed for destinations
+ if OpCode(c.Code[udest]) != BEGINSUB {
+ return false
+ }
+ return c.isCode(udest)
+}
+
+// isCode returns true if the provided PC location is an actual opcode, as
+// opposed to a data-segment following a PUSHN operation.
+func (c *Contract) isCode(udest uint64) bool {
+ // Do we already have an analysis laying around?
+ if c.analysis != nil {
+ return c.analysis.codeSegment(udest)
+ }
// Do we have a contract hash already?
+ // If we do have a hash, that means it's a 'regular' contract. For regular
+ // contracts ( not temporary initcode), we store the analysis in a map
if c.CodeHash != (common.Hash{}) {
// Does parent context have the analysis?
analysis, exist := c.jumpdests[c.CodeHash]
@@ -102,6 +128,8 @@ func (c *Contract) validJumpdest(dest *big.Int) bool {
analysis = codeBitmap(c.Code)
c.jumpdests[c.CodeHash] = analysis
}
+ // Also stash it in current contract for faster access
+ c.analysis = analysis
return analysis.codeSegment(udest)
}
// We don't have the code hash, most likely a piece of initcode not already
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index 54eab4e..9827bac 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -23,11 +23,14 @@ import (
"math/big"
"github.com/ava-labs/coreth/params"
- "github.com/ava-labs/go-ethereum/common"
- "github.com/ava-labs/go-ethereum/common/math"
- "github.com/ava-labs/go-ethereum/crypto"
- "github.com/ava-labs/go-ethereum/crypto/blake2b"
- "github.com/ava-labs/go-ethereum/crypto/bn256"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/crypto/blake2b"
+ "github.com/ethereum/go-ethereum/crypto/bls12381"
+ "github.com/ethereum/go-ethereum/crypto/bn256"
+
+ //lint:ignore SA1019 Needed for precompile
"golang.org/x/crypto/ripemd160"
)
@@ -75,13 +78,42 @@ var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{9}): &blake2F{},
}
+// PrecompiledContractsYoloV1 contains the default set of pre-compiled Ethereum
+// contracts used in the Yolo v1 test release.
+var PrecompiledContractsYoloV1 = map[common.Address]PrecompiledContract{
+ common.BytesToAddress([]byte{1}): &ecrecover{},
+ common.BytesToAddress([]byte{2}): &sha256hash{},
+ common.BytesToAddress([]byte{3}): &ripemd160hash{},
+ common.BytesToAddress([]byte{4}): &dataCopy{},
+ common.BytesToAddress([]byte{5}): &bigModExp{},
+ common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
+ common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
+ common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
+ common.BytesToAddress([]byte{9}): &blake2F{},
+ common.BytesToAddress([]byte{10}): &bls12381G1Add{},
+ common.BytesToAddress([]byte{11}): &bls12381G1Mul{},
+ common.BytesToAddress([]byte{12}): &bls12381G1MultiExp{},
+ common.BytesToAddress([]byte{13}): &bls12381G2Add{},
+ common.BytesToAddress([]byte{14}): &bls12381G2Mul{},
+ common.BytesToAddress([]byte{15}): &bls12381G2MultiExp{},
+ common.BytesToAddress([]byte{16}): &bls12381Pairing{},
+ common.BytesToAddress([]byte{17}): &bls12381MapG1{},
+ common.BytesToAddress([]byte{18}): &bls12381MapG2{},
+}
+
// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
-func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
- gas := p.RequiredGas(input)
- if contract.UseGas(gas) {
- return p.Run(input)
+// It returns
+// - the returned bytes,
+// - the _remaining_ gas,
+// - any error that occurred
+func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) {
+ gasCost := p.RequiredGas(input)
+ if suppliedGas < gasCost {
+ return nil, 0, ErrOutOfGas
}
- return nil, ErrOutOfGas
+ suppliedGas -= gasCost
+ output, err := p.Run(input)
+ return output, suppliedGas, err
}
// ECRECOVER implemented as a native contract.
@@ -106,8 +138,13 @@ func (c *ecrecover) Run(input []byte) ([]byte, error) {
if !allZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) {
return nil, nil
}
+ // We must make sure not to modify the 'input', so placing the 'v' along with
+ // the signature needs to be done on a new allocation
+ sig := make([]byte, 65)
+ copy(sig, input[64:128])
+ sig[64] = v
// v needs to be at the end for libsecp256k1
- pubKey, err := crypto.Ecrecover(input[:32], append(input[64:128], v))
+ pubKey, err := crypto.Ecrecover(input[:32], sig)
// make sure the public key is a valid one
if err != nil {
return nil, nil
@@ -166,6 +203,7 @@ func (c *dataCopy) Run(in []byte) ([]byte, error) {
type bigModExp struct{}
var (
+ big0 = big.NewInt(0)
big1 = big.NewInt(1)
big4 = big.NewInt(4)
big8 = big.NewInt(8)
@@ -458,7 +496,7 @@ var (
)
func (c *blake2F) Run(input []byte) ([]byte, error) {
- // Make sure the input is valid (correct lenth and final flag)
+ // Make sure the input is valid (correct length and final flag)
if len(input) != blake2FInputLength {
return nil, errBlake2FInvalidInputLength
}
@@ -495,3 +533,428 @@ func (c *blake2F) Run(input []byte) ([]byte, error) {
}
return output, nil
}
+
+var (
+ errBLS12381InvalidInputLength = errors.New("invalid input length")
+ errBLS12381InvalidFieldElementTopBytes = errors.New("invalid field element top bytes")
+ errBLS12381G1PointSubgroup = errors.New("g1 point is not on correct subgroup")
+ errBLS12381G2PointSubgroup = errors.New("g2 point is not on correct subgroup")
+)
+
+// bls12381G1Add implements EIP-2537 G1Add precompile.
+type bls12381G1Add struct{}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+func (c *bls12381G1Add) RequiredGas(input []byte) uint64 {
+ return params.Bls12381G1AddGas
+}
+
+func (c *bls12381G1Add) Run(input []byte) ([]byte, error) {
+ // Implements EIP-2537 G1Add precompile.
+ // > G1 addition call expects `256` bytes as an input that is interpreted as byte concatenation of two G1 points (`128` bytes each).
+ // > Output is an encoding of addition operation result - single G1 point (`128` bytes).
+ if len(input) != 256 {
+ return nil, errBLS12381InvalidInputLength
+ }
+ var err error
+ var p0, p1 *bls12381.PointG1
+
+ // Initialize G1
+ g := bls12381.NewG1()
+
+ // Decode G1 point p_0
+ if p0, err = g.DecodePoint(input[:128]); err != nil {
+ return nil, err
+ }
+ // Decode G1 point p_1
+ if p1, err = g.DecodePoint(input[128:]); err != nil {
+ return nil, err
+ }
+
+ // Compute r = p_0 + p_1
+ r := g.New()
+ g.Add(r, p0, p1)
+
+ // Encode the G1 point result into 128 bytes
+ return g.EncodePoint(r), nil
+}
+
+// bls12381G1Mul implements EIP-2537 G1Mul precompile.
+type bls12381G1Mul struct{}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+func (c *bls12381G1Mul) RequiredGas(input []byte) uint64 {
+ return params.Bls12381G1MulGas
+}
+
+func (c *bls12381G1Mul) Run(input []byte) ([]byte, error) {
+ // Implements EIP-2537 G1Mul precompile.
+ // > G1 multiplication call expects `160` bytes as an input that is interpreted as byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes).
+ // > Output is an encoding of multiplication operation result - single G1 point (`128` bytes).
+ if len(input) != 160 {
+ return nil, errBLS12381InvalidInputLength
+ }
+ var err error
+ var p0 *bls12381.PointG1
+
+ // Initialize G1
+ g := bls12381.NewG1()
+
+ // Decode G1 point
+ if p0, err = g.DecodePoint(input[:128]); err != nil {
+ return nil, err
+ }
+ // Decode scalar value
+ e := new(big.Int).SetBytes(input[128:])
+
+ // Compute r = e * p_0
+ r := g.New()
+ g.MulScalar(r, p0, e)
+
+ // Encode the G1 point into 128 bytes
+ return g.EncodePoint(r), nil
+}
+
+// bls12381G1MultiExp implements EIP-2537 G1MultiExp precompile.
+type bls12381G1MultiExp struct{}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 {
+ // Calculate G1 point, scalar value pair length
+ k := len(input) / 160
+ if k == 0 {
+ // Return 0 gas for small input length
+ return 0
+ }
+ // Lookup discount value for G1 point, scalar value pair length
+ var discount uint64
+ if dLen := len(params.Bls12381MultiExpDiscountTable); k < dLen {
+ discount = params.Bls12381MultiExpDiscountTable[k-1]
+ } else {
+ discount = params.Bls12381MultiExpDiscountTable[dLen-1]
+ }
+ // Calculate gas and return the result
+ return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000
+}
+
+func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) {
+ // Implements EIP-2537 G1MultiExp precompile.
+ // G1 multiplication call expects `160*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes).
+ // Output is an encoding of multiexponentiation operation result - single G1 point (`128` bytes).
+ k := len(input) / 160
+ if len(input) == 0 || len(input)%160 != 0 {
+ return nil, errBLS12381InvalidInputLength
+ }
+ var err error
+ points := make([]*bls12381.PointG1, k)
+ scalars := make([]*big.Int, k)
+
+ // Initialize G1
+ g := bls12381.NewG1()
+
+ // Decode point scalar pairs
+ for i := 0; i < k; i++ {
+ off := 160 * i
+ t0, t1, t2 := off, off+128, off+160
+ // Decode G1 point
+ if points[i], err = g.DecodePoint(input[t0:t1]); err != nil {
+ return nil, err
+ }
+ // Decode scalar value
+ scalars[i] = new(big.Int).SetBytes(input[t1:t2])
+ }
+
+ // Compute r = e_0 * p_0 + e_1 * p_1 + ... + e_(k-1) * p_(k-1)
+ r := g.New()
+ g.MultiExp(r, points, scalars)
+
+ // Encode the G1 point to 128 bytes
+ return g.EncodePoint(r), nil
+}
+
+// bls12381G2Add implements EIP-2537 G2Add precompile.
+type bls12381G2Add struct{}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+func (c *bls12381G2Add) RequiredGas(input []byte) uint64 {
+ return params.Bls12381G2AddGas
+}
+
+func (c *bls12381G2Add) Run(input []byte) ([]byte, error) {
+ // Implements EIP-2537 G2Add precompile.
+ // > G2 addition call expects `512` bytes as an input that is interpreted as byte concatenation of two G2 points (`256` bytes each).
+ // > Output is an encoding of addition operation result - single G2 point (`256` bytes).
+ if len(input) != 512 {
+ return nil, errBLS12381InvalidInputLength
+ }
+ var err error
+ var p0, p1 *bls12381.PointG2
+
+ // Initialize G2
+ g := bls12381.NewG2()
+ r := g.New()
+
+ // Decode G2 point p_0
+ if p0, err = g.DecodePoint(input[:256]); err != nil {
+ return nil, err
+ }
+ // Decode G2 point p_1
+ if p1, err = g.DecodePoint(input[256:]); err != nil {
+ return nil, err
+ }
+
+ // Compute r = p_0 + p_1
+ g.Add(r, p0, p1)
+
+ // Encode the G2 point into 256 bytes
+ return g.EncodePoint(r), nil
+}
+
+// bls12381G2Mul implements EIP-2537 G2Mul precompile.
+type bls12381G2Mul struct{}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+func (c *bls12381G2Mul) RequiredGas(input []byte) uint64 {
+ return params.Bls12381G2MulGas
+}
+
+func (c *bls12381G2Mul) Run(input []byte) ([]byte, error) {
+ // Implements EIP-2537 G2MUL precompile logic.
+ // > G2 multiplication call expects `288` bytes as an input that is interpreted as byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes).
+ // > Output is an encoding of multiplication operation result - single G2 point (`256` bytes).
+ if len(input) != 288 {
+ return nil, errBLS12381InvalidInputLength
+ }
+ var err error
+ var p0 *bls12381.PointG2
+
+ // Initialize G2
+ g := bls12381.NewG2()
+
+ // Decode G2 point
+ if p0, err = g.DecodePoint(input[:256]); err != nil {
+ return nil, err
+ }
+ // Decode scalar value
+ e := new(big.Int).SetBytes(input[256:])
+
+ // Compute r = e * p_0
+ r := g.New()
+ g.MulScalar(r, p0, e)
+
+ // Encode the G2 point into 256 bytes
+ return g.EncodePoint(r), nil
+}
+
+// bls12381G2MultiExp implements EIP-2537 G2MultiExp precompile.
+type bls12381G2MultiExp struct{}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 {
+ // Calculate G2 point, scalar value pair length
+ k := len(input) / 288
+ if k == 0 {
+ // Return 0 gas for small input length
+ return 0
+ }
+ // Lookup discount value for G2 point, scalar value pair length
+ var discount uint64
+ if dLen := len(params.Bls12381MultiExpDiscountTable); k < dLen {
+ discount = params.Bls12381MultiExpDiscountTable[k-1]
+ } else {
+ discount = params.Bls12381MultiExpDiscountTable[dLen-1]
+ }
+ // Calculate gas and return the result
+ return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000
+}
+
+func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) {
+ // Implements EIP-2537 G2MultiExp precompile logic
+ // > G2 multiplication call expects `288*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes).
+ // > Output is an encoding of multiexponentiation operation result - single G2 point (`256` bytes).
+ k := len(input) / 288
+ if len(input) == 0 || len(input)%288 != 0 {
+ return nil, errBLS12381InvalidInputLength
+ }
+ var err error
+ points := make([]*bls12381.PointG2, k)
+ scalars := make([]*big.Int, k)
+
+ // Initialize G2
+ g := bls12381.NewG2()
+
+ // Decode point scalar pairs
+ for i := 0; i < k; i++ {
+ off := 288 * i
+ t0, t1, t2 := off, off+256, off+288
+ // Decode G1 point
+ if points[i], err = g.DecodePoint(input[t0:t1]); err != nil {
+ return nil, err
+ }
+ // Decode scalar value
+ scalars[i] = new(big.Int).SetBytes(input[t1:t2])
+ }
+
+ // Compute r = e_0 * p_0 + e_1 * p_1 + ... + e_(k-1) * p_(k-1)
+ r := g.New()
+ g.MultiExp(r, points, scalars)
+
+ // Encode the G2 point to 256 bytes.
+ return g.EncodePoint(r), nil
+}
+
+// bls12381Pairing implements EIP-2537 Pairing precompile.
+type bls12381Pairing struct{}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+func (c *bls12381Pairing) RequiredGas(input []byte) uint64 {
+ return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas
+}
+
+func (c *bls12381Pairing) Run(input []byte) ([]byte, error) {
+ // Implements EIP-2537 Pairing precompile logic.
+ // > Pairing call expects `384*k` bytes as an inputs that is interpreted as byte concatenation of `k` slices. Each slice has the following structure:
+ // > - `128` bytes of G1 point encoding
+ // > - `256` bytes of G2 point encoding
+ // > Output is a `32` bytes where last single byte is `0x01` if pairing result is equal to multiplicative identity in a pairing target field and `0x00` otherwise
+ // > (which is equivalent of Big Endian encoding of Solidity values `uint256(1)` and `uin256(0)` respectively).
+ k := len(input) / 384
+ if len(input) == 0 || len(input)%384 != 0 {
+ return nil, errBLS12381InvalidInputLength
+ }
+
+ // Initialize BLS12-381 pairing engine
+ e := bls12381.NewPairingEngine()
+ g1, g2 := e.G1, e.G2
+
+ // Decode pairs
+ for i := 0; i < k; i++ {
+ off := 384 * i
+ t0, t1, t2 := off, off+128, off+384
+
+ // Decode G1 point
+ p1, err := g1.DecodePoint(input[t0:t1])
+ if err != nil {
+ return nil, err
+ }
+ // Decode G2 point
+ p2, err := g2.DecodePoint(input[t1:t2])
+ if err != nil {
+ return nil, err
+ }
+
+ // 'point is on curve' check already done,
+ // Here we need to apply subgroup checks.
+ if !g1.InCorrectSubgroup(p1) {
+ return nil, errBLS12381G1PointSubgroup
+ }
+ if !g2.InCorrectSubgroup(p2) {
+ return nil, errBLS12381G2PointSubgroup
+ }
+
+ // Update pairing engine with G1 and G2 ponits
+ e.AddPair(p1, p2)
+ }
+ // Prepare 32 byte output
+ out := make([]byte, 32)
+
+ // Compute pairing and set the result
+ if e.Check() {
+ out[31] = 1
+ }
+ return out, nil
+}
+
+// decodeBLS12381FieldElement decodes BLS12-381 elliptic curve field element.
+// Removes top 16 bytes of 64 byte input.
+func decodeBLS12381FieldElement(in []byte) ([]byte, error) {
+ if len(in) != 64 {
+ return nil, errors.New("invalid field element length")
+ }
+ // check top bytes
+ for i := 0; i < 16; i++ {
+ if in[i] != byte(0x00) {
+ return nil, errBLS12381InvalidFieldElementTopBytes
+ }
+ }
+ out := make([]byte, 48)
+ copy(out[:], in[16:])
+ return out, nil
+}
+
+// bls12381MapG1 implements EIP-2537 MapG1 precompile.
+type bls12381MapG1 struct{}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+func (c *bls12381MapG1) RequiredGas(input []byte) uint64 {
+ return params.Bls12381MapG1Gas
+}
+
+func (c *bls12381MapG1) Run(input []byte) ([]byte, error) {
+ // Implements EIP-2537 Map_To_G1 precompile.
+ // > Field-to-curve call expects `64` bytes an an input that is interpreted as a an element of the base field.
+ // > Output of this call is `128` bytes and is G1 point following respective encoding rules.
+ if len(input) != 64 {
+ return nil, errBLS12381InvalidInputLength
+ }
+
+ // Decode input field element
+ fe, err := decodeBLS12381FieldElement(input)
+ if err != nil {
+ return nil, err
+ }
+
+ // Initialize G1
+ g := bls12381.NewG1()
+
+ // Compute mapping
+ r, err := g.MapToCurve(fe)
+ if err != nil {
+ return nil, err
+ }
+
+ // Encode the G1 point to 128 bytes
+ return g.EncodePoint(r), nil
+}
+
+// bls12381MapG2 implements EIP-2537 MapG2 precompile.
+type bls12381MapG2 struct{}
+
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+func (c *bls12381MapG2) RequiredGas(input []byte) uint64 {
+ return params.Bls12381MapG2Gas
+}
+
+func (c *bls12381MapG2) Run(input []byte) ([]byte, error) {
+ // Implements EIP-2537 Map_FP2_TO_G2 precompile logic.
+ // > Field-to-curve call expects `128` bytes an an input that is interpreted as a an element of the quadratic extension field.
+ // > Output of this call is `256` bytes and is G2 point following respective encoding rules.
+ if len(input) != 128 {
+ return nil, errBLS12381InvalidInputLength
+ }
+
+ // Decode input field element
+ fe := make([]byte, 96)
+ c0, err := decodeBLS12381FieldElement(input[:64])
+ if err != nil {
+ return nil, err
+ }
+ copy(fe[48:], c0)
+ c1, err := decodeBLS12381FieldElement(input[64:])
+ if err != nil {
+ return nil, err
+ }
+ copy(fe[:48], c1)
+
+ // Initialize G2
+ g := bls12381.NewG2()
+
+ // Compute mapping
+ r, err := g.MapToCurve(fe)
+ if err != nil {
+ return nil, err
+ }
+
+ // Encode the G2 point to 256 bytes
+ return g.EncodePoint(r), nil
+}
diff --git a/core/vm/eips.go b/core/vm/eips.go
index 75e5fb1..5ec7587 100644
--- a/core/vm/eips.go
+++ b/core/vm/eips.go
@@ -18,27 +18,44 @@ package vm
import (
"fmt"
+ "sort"
"github.com/ava-labs/coreth/params"
+ "github.com/holiman/uint256"
)
+var activators = map[int]func(*JumpTable){
+ 2200: enable2200,
+ 1884: enable1884,
+ 1344: enable1344,
+ 2315: enable2315,
+}
+
// EnableEIP enables the given EIP on the config.
// This operation writes in-place, and callers need to ensure that the globally
// defined jump tables are not polluted.
func EnableEIP(eipNum int, jt *JumpTable) error {
- switch eipNum {
- case 2200:
- enable2200(jt)
- case 1884:
- enable1884(jt)
- case 1344:
- enable1344(jt)
- default:
+ enablerFn, ok := activators[eipNum]
+ if !ok {
return fmt.Errorf("undefined eip %d", eipNum)
}
+ enablerFn(jt)
return nil
}
+func ValidEip(eipNum int) bool {
+ _, ok := activators[eipNum]
+ return ok
+}
+func ActivateableEips() []string {
+ var nums []string
+ for k := range activators {
+ nums = append(nums, fmt.Sprintf("%d", k))
+ }
+ sort.Strings(nums)
+ return nums
+}
+
// enable1884 applies EIP-1884 to the given jump table:
// - Increase cost of BALANCE to 700
// - Increase cost of EXTCODEHASH to 700
@@ -46,23 +63,22 @@ func EnableEIP(eipNum int, jt *JumpTable) error {
// - Define SELFBALANCE, with cost GasFastStep (5)
func enable1884(jt *JumpTable) {
// Gas cost changes
+ jt[SLOAD].constantGas = params.SloadGasEIP1884
jt[BALANCE].constantGas = params.BalanceGasEIP1884
jt[EXTCODEHASH].constantGas = params.ExtcodeHashGasEIP1884
- jt[SLOAD].constantGas = params.SloadGasEIP1884
// New opcode
- jt[SELFBALANCE] = operation{
+ jt[SELFBALANCE] = &operation{
execute: opSelfBalance,
constantGas: GasFastStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
}
}
-func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- balance := interpreter.intPool.get().Set(interpreter.evm.StateDB.GetBalance(contract.Address()))
- stack.push(balance)
+func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
+ balance, _ := uint256.FromBig(interpreter.evm.StateDB.GetBalance(callContext.contract.Address()))
+ callContext.stack.push(balance)
return nil, nil
}
@@ -70,23 +86,51 @@ func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract,
// - Adds an opcode that returns the current chain’s EIP-155 unique identifier
func enable1344(jt *JumpTable) {
// New opcode
- jt[CHAINID] = operation{
+ jt[CHAINID] = &operation{
execute: opChainID,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
- valid: true,
}
}
// opChainID implements CHAINID opcode
-func opChainID(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- chainId := interpreter.intPool.get().Set(interpreter.evm.chainConfig.ChainID)
- stack.push(chainId)
+func opChainID(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
+ chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainID)
+ callContext.stack.push(chainId)
return nil, nil
}
// enable2200 applies EIP-2200 (Rebalance net-metered SSTORE)
func enable2200(jt *JumpTable) {
+ jt[SLOAD].constantGas = params.SloadGasEIP2200
jt[SSTORE].dynamicGas = gasSStoreEIP2200
}
+
+// enable2315 applies EIP-2315 (Simple Subroutines)
+// - Adds opcodes that jump to and return from subroutines
+func enable2315(jt *JumpTable) {
+ // New opcode
+ jt[BEGINSUB] = &operation{
+ execute: opBeginSub,
+ constantGas: GasQuickStep,
+ minStack: minStack(0, 0),
+ maxStack: maxStack(0, 0),
+ }
+ // New opcode
+ jt[JUMPSUB] = &operation{
+ execute: opJumpSub,
+ constantGas: GasSlowStep,
+ minStack: minStack(1, 0),
+ maxStack: maxStack(1, 0),
+ jumps: true,
+ }
+ // New opcode
+ jt[RETURNSUB] = &operation{
+ execute: opReturnSub,
+ constantGas: GasFastStep,
+ minStack: minStack(0, 0),
+ maxStack: maxStack(0, 0),
+ jumps: true,
+ }
+}
diff --git a/core/vm/errors.go b/core/vm/errors.go
index 94f0ed8..9f3f335 100644
--- a/core/vm/errors.go
+++ b/core/vm/errors.go
@@ -16,16 +16,57 @@
package vm
-import "errors"
+import (
+ "errors"
+ "fmt"
+)
-// List execution errors
+// List evm execution errors
var (
+ // ErrInvalidSubroutineEntry means that a BEGINSUB was reached via iteration,
+ // as opposed to from a JUMPSUB instruction
+ ErrInvalidSubroutineEntry = errors.New("invalid subroutine entry")
ErrOutOfGas = errors.New("out of gas")
ErrCodeStoreOutOfGas = errors.New("contract creation code storage out of gas")
ErrDepth = errors.New("max call depth exceeded")
- ErrTraceLimitReached = errors.New("the number of logs reached the specified limit")
ErrInsufficientBalance = errors.New("insufficient balance for transfer")
ErrIncompatibleAccount = errors.New("incompatible account")
ErrContractAddressCollision = errors.New("contract address collision")
- ErrNoCompatibleInterpreter = errors.New("no compatible interpreter")
+ ErrExecutionReverted = errors.New("execution reverted")
+ ErrMaxCodeSizeExceeded = errors.New("max code size exceeded")
+ ErrInvalidJump = errors.New("invalid jump destination")
+ ErrWriteProtection = errors.New("write protection")
+ ErrReturnDataOutOfBounds = errors.New("return data out of bounds")
+ ErrGasUintOverflow = errors.New("gas uint64 overflow")
+ ErrInvalidRetsub = errors.New("invalid retsub")
+ ErrReturnStackExceeded = errors.New("return stack limit reached")
)
+
+// ErrStackUnderflow wraps an evm error when the items on the stack less
+// than the minimal requirement.
+type ErrStackUnderflow struct {
+ stackLen int
+ required int
+}
+
+func (e *ErrStackUnderflow) Error() string {
+ return fmt.Sprintf("stack underflow (%d <=> %d)", e.stackLen, e.required)
+}
+
+// ErrStackOverflow wraps an evm error when the items on the stack exceeds
+// the maximum allowance.
+type ErrStackOverflow struct {
+ stackLen int
+ limit int
+}
+
+func (e *ErrStackOverflow) Error() string {
+ return fmt.Sprintf("stack limit reached %d (%d)", e.stackLen, e.limit)
+}
+
+// ErrInvalidOpCode wraps an evm error when an invalid opcode is encountered.
+type ErrInvalidOpCode struct {
+ opcode OpCode
+}
+
+func (e *ErrInvalidOpCode) Error() string { return fmt.Sprintf("invalid opcode: %s", e.opcode) }
diff --git a/core/vm/evm.go b/core/vm/evm.go
index be8b240..e895211 100644
--- a/