aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authoraaronbuchwald <[email protected]>2020-12-15 21:31:57 -0500
committerGitHub <[email protected]>2020-12-15 21:31:57 -0500
commit3f055c40405b44ba1e606578c08b1e8f0ca7e026 (patch)
tree6569bcfe3a62f3804a4f90b803b3d0d6cd96d732 /core
parent2d0a37c6490dc9a4ec36ee4ebbed01c790f0426a (diff)
parent7c758da302baf80775876008958ec77055ab953a (diff)
Merge pull request #56 from ava-labs/mc-transfer
Mc transfer
Diffstat (limited to 'core')
-rw-r--r--core/vm/contracts.go86
-rw-r--r--core/vm/contracts_stateful.go165
-rw-r--r--core/vm/evm.go24
-rw-r--r--core/vm/interpreter.go12
-rw-r--r--core/vm/jump_table.go11
-rw-r--r--core/vm/opcodes.go1
6 files changed, 246 insertions, 53 deletions
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index 9827bac..6fc6334 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -44,61 +44,61 @@ type PrecompiledContract interface {
// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum
// contracts used in the Frontier and Homestead releases.
-var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{
- common.BytesToAddress([]byte{1}): &ecrecover{},
- common.BytesToAddress([]byte{2}): &sha256hash{},
- common.BytesToAddress([]byte{3}): &ripemd160hash{},
- common.BytesToAddress([]byte{4}): &dataCopy{},
+var PrecompiledContractsHomestead = map[common.Address]StatefulPrecompiledContract{
+ common.BytesToAddress([]byte{1}): newWrappedPrecompiledContract(&ecrecover{}),
+ common.BytesToAddress([]byte{2}): newWrappedPrecompiledContract(&sha256hash{}),
+ common.BytesToAddress([]byte{3}): newWrappedPrecompiledContract(&ripemd160hash{}),
+ common.BytesToAddress([]byte{4}): newWrappedPrecompiledContract(&dataCopy{}),
}
// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
// contracts used in the Byzantium release.
-var PrecompiledContractsByzantium = 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}): &bn256AddByzantium{},
- common.BytesToAddress([]byte{7}): &bn256ScalarMulByzantium{},
- common.BytesToAddress([]byte{8}): &bn256PairingByzantium{},
+var PrecompiledContractsByzantium = map[common.Address]StatefulPrecompiledContract{
+ common.BytesToAddress([]byte{1}): newWrappedPrecompiledContract(&ecrecover{}),
+ common.BytesToAddress([]byte{2}): newWrappedPrecompiledContract(&sha256hash{}),
+ common.BytesToAddress([]byte{3}): newWrappedPrecompiledContract(&ripemd160hash{}),
+ common.BytesToAddress([]byte{4}): newWrappedPrecompiledContract(&dataCopy{}),
+ common.BytesToAddress([]byte{5}): newWrappedPrecompiledContract(&bigModExp{}),
+ common.BytesToAddress([]byte{6}): newWrappedPrecompiledContract(&bn256AddByzantium{}),
+ common.BytesToAddress([]byte{7}): newWrappedPrecompiledContract(&bn256ScalarMulByzantium{}),
+ common.BytesToAddress([]byte{8}): newWrappedPrecompiledContract(&bn256PairingByzantium{}),
}
// PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum
// contracts used in the Istanbul release.
-var PrecompiledContractsIstanbul = 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{},
+var PrecompiledContractsIstanbul = map[common.Address]StatefulPrecompiledContract{
+ common.BytesToAddress([]byte{1}): newWrappedPrecompiledContract(&ecrecover{}),
+ common.BytesToAddress([]byte{2}): newWrappedPrecompiledContract(&sha256hash{}),
+ common.BytesToAddress([]byte{3}): newWrappedPrecompiledContract(&ripemd160hash{}),
+ common.BytesToAddress([]byte{4}): newWrappedPrecompiledContract(&dataCopy{}),
+ common.BytesToAddress([]byte{5}): newWrappedPrecompiledContract(&bigModExp{}),
+ common.BytesToAddress([]byte{6}): newWrappedPrecompiledContract(&bn256AddIstanbul{}),
+ common.BytesToAddress([]byte{7}): newWrappedPrecompiledContract(&bn256ScalarMulIstanbul{}),
+ common.BytesToAddress([]byte{8}): newWrappedPrecompiledContract(&bn256PairingIstanbul{}),
+ common.BytesToAddress([]byte{9}): newWrappedPrecompiledContract(&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{},
+var PrecompiledContractsYoloV1 = map[common.Address]StatefulPrecompiledContract{
+ common.BytesToAddress([]byte{1}): newWrappedPrecompiledContract(&ecrecover{}),
+ common.BytesToAddress([]byte{2}): newWrappedPrecompiledContract(&sha256hash{}),
+ common.BytesToAddress([]byte{3}): newWrappedPrecompiledContract(&ripemd160hash{}),
+ common.BytesToAddress([]byte{4}): newWrappedPrecompiledContract(&dataCopy{}),
+ common.BytesToAddress([]byte{5}): newWrappedPrecompiledContract(&bigModExp{}),
+ common.BytesToAddress([]byte{6}): newWrappedPrecompiledContract(&bn256AddIstanbul{}),
+ common.BytesToAddress([]byte{7}): newWrappedPrecompiledContract(&bn256ScalarMulIstanbul{}),
+ common.BytesToAddress([]byte{8}): newWrappedPrecompiledContract(&bn256PairingIstanbul{}),
+ common.BytesToAddress([]byte{9}): newWrappedPrecompiledContract(&blake2F{}),
+ common.BytesToAddress([]byte{10}): newWrappedPrecompiledContract(&bls12381G1Add{}),
+ common.BytesToAddress([]byte{11}): newWrappedPrecompiledContract(&bls12381G1Mul{}),
+ common.BytesToAddress([]byte{12}): newWrappedPrecompiledContract(&bls12381G1MultiExp{}),
+ common.BytesToAddress([]byte{13}): newWrappedPrecompiledContract(&bls12381G2Add{}),
+ common.BytesToAddress([]byte{14}): newWrappedPrecompiledContract(&bls12381G2Mul{}),
+ common.BytesToAddress([]byte{15}): newWrappedPrecompiledContract(&bls12381G2MultiExp{}),
+ common.BytesToAddress([]byte{16}): newWrappedPrecompiledContract(&bls12381Pairing{}),
+ common.BytesToAddress([]byte{17}): newWrappedPrecompiledContract(&bls12381MapG1{}),
+ common.BytesToAddress([]byte{18}): newWrappedPrecompiledContract(&bls12381MapG2{}),
}
// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
diff --git a/core/vm/contracts_stateful.go b/core/vm/contracts_stateful.go
new file mode 100644
index 0000000..b91acfb
--- /dev/null
+++ b/core/vm/contracts_stateful.go
@@ -0,0 +1,165 @@
+package vm
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+
+ "github.com/ava-labs/coreth/params"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/holiman/uint256"
+)
+
+// PrecompiledContractsApricot contains the default set of pre-compiled Ethereum
+// contracts used in the Istanbul release and the stateful precompiled contracts
+// added for the Avalanche Apricot release.
+// Apricot is incompatible with the YoloV1 Release since it does not include the
+// BLS12-381 Curve Operations added to the set of precompiled contracts
+var PrecompiledContractsApricot = map[common.Address]StatefulPrecompiledContract{
+ common.BytesToAddress([]byte{1}): newWrappedPrecompiledContract(&ecrecover{}),
+ common.BytesToAddress([]byte{2}): newWrappedPrecompiledContract(&sha256hash{}),
+ common.BytesToAddress([]byte{3}): newWrappedPrecompiledContract(&ripemd160hash{}),
+ common.BytesToAddress([]byte{4}): newWrappedPrecompiledContract(&dataCopy{}),
+ common.BytesToAddress([]byte{5}): newWrappedPrecompiledContract(&bigModExp{}),
+ common.BytesToAddress([]byte{6}): newWrappedPrecompiledContract(&bn256AddIstanbul{}),
+ common.BytesToAddress([]byte{7}): newWrappedPrecompiledContract(&bn256ScalarMulIstanbul{}),
+ common.BytesToAddress([]byte{8}): newWrappedPrecompiledContract(&bn256PairingIstanbul{}),
+ common.BytesToAddress([]byte{9}): newWrappedPrecompiledContract(&blake2F{}),
+ common.HexToAddress("0x0100000000000000000000000000000000000000"): &deprecatedContract{msg: "hardcoded genesis contract has been deprecated"},
+ common.HexToAddress("0x0100000000000000000000000000000000000001"): &nativeAssetBalance{gasCost: params.AssetBalanceApricot},
+ common.HexToAddress("0x0100000000000000000000000000000000000002"): &nativeAssetCall{gasCost: params.AssetCallApricot},
+}
+
+// StatefulPrecompiledContract is the interface for executing a precompiled contract
+// This wraps the PrecompiledContracts native to Ethereum and allows adding in stateful
+// precompiled contracts to support native Avalanche asset transfers.
+type StatefulPrecompiledContract interface {
+ // Run executes a precompiled contract in the current state
+ // assumes that it has already been verified that [caller] can
+ // transfer [value].
+ Run(evm *EVM, caller ContractRef, addr common.Address, value *big.Int, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error)
+}
+
+// wrappedPrecompiledContract implements StatefulPrecompiledContract by wrapping stateless native precompiled contracts
+// in Ethereum.
+type wrappedPrecompiledContract struct {
+ p PrecompiledContract
+}
+
+func newWrappedPrecompiledContract(p PrecompiledContract) StatefulPrecompiledContract {
+ return &wrappedPrecompiledContract{p: p}
+}
+
+// Run ...
+func (w *wrappedPrecompiledContract) Run(evm *EVM, caller ContractRef, addr common.Address, value *big.Int, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
+ evm.Transfer(evm.StateDB, caller.Address(), addr, value)
+ return RunPrecompiledContract(w.p, input, suppliedGas)
+}
+
+// nativeAssetBalance is a precompiled contract used to retrieve the native asset balance
+type nativeAssetBalance struct {
+ gasCost uint64
+}
+
+// Run implements StatefulPrecompiledContract
+func (b *nativeAssetBalance) Run(evm *EVM, caller ContractRef, addr common.Address, value *big.Int, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
+ // input: encodePacked(address 20 bytes, assetID 32 bytes)
+ if value.Sign() != 0 {
+ return nil, suppliedGas, errors.New("cannot transfer value to native asset balance pre-compiled contract")
+ }
+
+ if suppliedGas < b.gasCost {
+ return nil, 0, ErrOutOfGas
+ }
+ remainingGas = suppliedGas - b.gasCost
+
+ if len(input) != 52 {
+ return nil, remainingGas, fmt.Errorf("input to native asset balance must be 52 bytes, containing address [20 bytes] and assetID [32 bytes], but found length: %d", len(input))
+ }
+ address := common.BytesToAddress(input[:20])
+ assetID := new(common.Hash)
+ assetID.SetBytes(input[20:52])
+
+ res, overflow := uint256.FromBig(evm.StateDB.GetBalanceMultiCoin(address, *assetID))
+ log.Info("nativeAssetBalance", "address", address, "assetID", assetID.Hex(), "res", res, "overflow", overflow)
+ if overflow {
+ return nil, remainingGas, errors.New("balance overflow")
+ }
+ return common.LeftPadBytes(res.Bytes(), 32), remainingGas, nil
+}
+
+// nativeAssetCall atomically transfers a native asset to a recipient address as well as calling that
+// address
+type nativeAssetCall struct {
+ gasCost uint64
+}
+
+// Run implements StatefulPrecompiledContract
+func (c *nativeAssetCall) Run(evm *EVM, caller ContractRef, addr common.Address, value *big.Int, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
+ // input: encodePacked(address 20 bytes, assetID 32 bytes, assetAmount 32 bytes, callData variable length bytes)
+ if suppliedGas < c.gasCost {
+ return nil, 0, ErrOutOfGas
+ }
+ remainingGas = suppliedGas - c.gasCost
+
+ if readOnly {
+ return nil, remainingGas, errors.New("cannot execute native asset transfer within read only call")
+ }
+
+ if len(input) < 84 {
+ return nil, remainingGas, fmt.Errorf("missing inputs to native asset transfer, expected input of length at least 84, but found %d", len(input))
+ }
+ to := common.BytesToAddress(input[:20])
+ assetID := new(common.Hash)
+ assetID.SetBytes(input[20:52])
+ assetAmount := new(big.Int).SetBytes(input[52:84])
+ callData := input[84:]
+ log.Info("nativeAssetCall", "input", fmt.Sprintf("0x%x", input), "to", to.Hex(), "assetID", assetID.Hex(), "assetAmount", assetAmount, "callData", fmt.Sprintf("0x%x", callData))
+
+ mcerr := evm.Context.CanTransferMC(evm.StateDB, caller.Address(), to, assetID, assetAmount)
+ if mcerr == 1 {
+ log.Info("Insufficient balance for mc transfer")
+ return nil, remainingGas, ErrInsufficientBalance
+ } else if mcerr != 0 {
+ log.Info("incompatible account for mc transfer")
+ return nil, remainingGas, ErrIncompatibleAccount
+ }
+
+ snapshot := evm.StateDB.Snapshot()
+
+ if !evm.StateDB.Exist(to) {
+ log.Info("Creating account entry", "address", to.Hex())
+ remainingGas -= params.CallNewAccountGas
+ evm.StateDB.CreateAccount(to)
+ }
+
+ // Send [value] to [to] address
+ evm.Transfer(evm.StateDB, caller.Address(), to, value)
+ evm.TransferMultiCoin(evm.StateDB, caller.Address(), to, assetID, assetAmount)
+ ret, remainingGas, err = evm.Call(caller, to, callData, remainingGas, big.NewInt(0))
+ log.Info("Finished TransferMultiCoin and call", "return", ret, "remainingGas", remainingGas, "error", err)
+
+ // When an error was returned by the EVM or when setting the creation code
+ // above we revert to the snapshot and consume any gas remaining. Additionally
+ // when we're in homestead this also counts for code storage gas errors.
+ if err != nil {
+ evm.StateDB.RevertToSnapshot(snapshot)
+ if err != ErrExecutionReverted {
+ remainingGas = 0
+ }
+ // TODO: consider clearing up unused snapshots:
+ //} else {
+ // evm.StateDB.DiscardSnapshot(snapshot)
+ }
+ return ret, remainingGas, err
+}
+
+type deprecatedContract struct {
+ msg string
+}
+
+// Run ...
+func (d *deprecatedContract) Run(evm *EVM, caller ContractRef, addr common.Address, value *big.Int, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
+ return nil, suppliedGas, errors.New(d.msg)
+}
diff --git a/core/vm/evm.go b/core/vm/evm.go
index 54c9c7f..fe840da 100644
--- a/core/vm/evm.go
+++ b/core/vm/evm.go
@@ -34,19 +34,23 @@ var emptyCodeHash = crypto.Keccak256Hash(nil)
type (
// CanTransferFunc is the signature of a transfer guard function
- CanTransferFunc func(StateDB, common.Address, *big.Int) bool
+ CanTransferFunc func(StateDB, common.Address, *big.Int) bool
+ // CanTransferMCFunc is the signature of a transfer native asset function
CanTransferMCFunc func(StateDB, common.Address, common.Address, *common.Hash, *big.Int) int
// TransferFunc is the signature of a transfer function
- TransferFunc func(StateDB, common.Address, common.Address, *big.Int)
+ TransferFunc func(StateDB, common.Address, common.Address, *big.Int)
+ // TransferMCFunc is the signature of a transfer native asset function
TransferMCFunc func(StateDB, common.Address, common.Address, *common.Hash, *big.Int)
// GetHashFunc returns the n'th block hash in the blockchain
// and is used by the BLOCKHASH EVM op code.
GetHashFunc func(uint64) common.Hash
)
-func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
- var precompiles map[common.Address]PrecompiledContract
+func (evm *EVM) precompile(addr common.Address) (StatefulPrecompiledContract, bool) {
+ var precompiles map[common.Address]StatefulPrecompiledContract
switch {
+ case evm.chainRules.IsApricot:
+ precompiles = PrecompiledContractsApricot
case evm.chainRules.IsYoloV1:
precompiles = PrecompiledContractsYoloV1
case evm.chainRules.IsIstanbul:
@@ -148,7 +152,7 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon
StateDB: statedb,
vmConfig: vmConfig,
chainConfig: chainConfig,
- chainRules: chainConfig.Rules(ctx.BlockNumber),
+ chainRules: chainConfig.AvalancheRules(ctx.BlockNumber, ctx.Time),
interpreters: make([]Interpreter, 0, 1),
}
@@ -222,7 +226,6 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
}
evm.StateDB.CreateAccount(addr)
}
- evm.Transfer(evm.StateDB, caller.Address(), addr, value)
// Capture the tracer start/end events in debug mode
if evm.vmConfig.Debug && evm.depth == 0 {
@@ -233,8 +236,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
}
if isPrecompile {
- ret, gas, err = RunPrecompiledContract(p, input, gas)
+ ret, gas, err = p.Run(evm, caller, addr, value, input, gas, false)
} else {
+ evm.Transfer(evm.StateDB, caller.Address(), addr, value)
// Initialise a new contract and set the code that is to be used by the EVM.
// The contract is a scoped environment for this execution context only.
code := evm.StateDB.GetCode(addr)
@@ -371,7 +375,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
// It is allowed to call precompiles, even via delegatecall
if p, isPrecompile := evm.precompile(addr); isPrecompile {
- ret, gas, err = RunPrecompiledContract(p, input, gas)
+ ret, gas, err = p.Run(evm, caller, addr, value, input, gas, false)
} else {
addrCopy := addr
// Initialise a new contract and set the code that is to be used by the EVM.
@@ -407,7 +411,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
// It is allowed to call precompiles, even via delegatecall
if p, isPrecompile := evm.precompile(addr); isPrecompile {
- ret, gas, err = RunPrecompiledContract(p, input, gas)
+ ret, gas, err = p.Run(evm, caller, addr, big0, input, gas, false)
} else {
addrCopy := addr
// Initialise a new contract and make initialise the delegate values
@@ -451,7 +455,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
evm.StateDB.AddBalance(addr, big0)
if p, isPrecompile := evm.precompile(addr); isPrecompile {
- ret, gas, err = RunPrecompiledContract(p, input, gas)
+ ret, gas, err = p.Run(evm, caller, addr, big0, input, gas, true)
} else {
// At this point, we use a copy of address. If we don't, the go compiler will
// leak the 'contract' to the outer scope, and make allocation for 'contract'
diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go
index a114a8d..1292650 100644
--- a/core/vm/interpreter.go
+++ b/core/vm/interpreter.go
@@ -26,6 +26,7 @@ import (
)
var (
+ // BuiltinAddr ...
BuiltinAddr = common.Address{
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -106,6 +107,8 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
if cfg.JumpTable[STOP] == nil {
var jt JumpTable
switch {
+ case evm.chainRules.IsApricot:
+ jt = apricotInstructionSet
case evm.chainRules.IsYoloV1:
jt = yoloV1InstructionSet
case evm.chainRules.IsIstanbul:
@@ -146,6 +149,15 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
// considered a revert-and-consume-all-gas operation except for
// ErrExecutionReverted which means revert-and-keep-gas-left.
func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) {
+ // TODO remove after Apricot network upgrade.
+ // [BuiltinAddr] is overridden by a precompile in Apricot.
+ // This makes any call to [BuiltinAddr] a no-op once the network
+ // upgrade occurs. Then in the upgrade after the hard fork, this
+ // code can be safely removed.
+ // This can't occur before the hard fork because it would change
+ // the behavior of upgraded nodes before the hard fork occurs
+ // since there is no mechanism to change this code based on the
+ // block height.
if contract.Address() == BuiltinAddr {
self := AccountRef(contract.Caller())
if _, ok := contract.caller.(*Contract); ok {
diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go
index 9b538d4..44e2ebc 100644
--- a/core/vm/jump_table.go
+++ b/core/vm/jump_table.go
@@ -49,6 +49,7 @@ type operation struct {
}
var (
+ apricotInstructionSet = newApricotInstructionSet()
frontierInstructionSet = newFrontierInstructionSet()
homesteadInstructionSet = newHomesteadInstructionSet()
tangerineWhistleInstructionSet = newTangerineWhistleInstructionSet()
@@ -62,6 +63,16 @@ var (
// JumpTable contains the EVM opcodes supported at a given fork.
type JumpTable [256]*operation
+// newApricotInstructionSet returns a new instruction set
+// compatible with the Apricot release, which deprecates
+// added instructions: CALLEX and BALANCEMC
+func newApricotInstructionSet() JumpTable {
+ instructionSet := newIstanbulInstructionSet()
+ instructionSet[CALLEX] = nil
+ instructionSet[BALANCEMC] = nil
+ return instructionSet
+}
+
func newYoloV1InstructionSet() JumpTable {
instructionSet := newIstanbulInstructionSet()
diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go
index c5097f8..cc9518e 100644
--- a/core/vm/opcodes.go
+++ b/core/vm/opcodes.go
@@ -208,6 +208,7 @@ const (
SWAP
)
+// Constants supporting native asset operations
const (
BALANCEMC = 0xcd
//EMC = 0xce