Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
d6da4342
Commit
d6da4342
authored
Sep 13, 2021
by
George Hotz
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
further
parent
ffaa1784
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
656 additions
and
2 deletions
+656
-2
error.go
minigeth/core/error.go
+93
-0
evm.go
minigeth/core/evm.go
+119
-0
gaspool.go
minigeth/core/gaspool.go
+54
-0
state_processor.go
minigeth/core/state_processor.go
+4
-2
state_transition.go
minigeth/core/state_transition.go
+365
-0
interpreter.go
minigeth/core/vm/interpreter.go
+21
-0
No files found.
minigeth/core/error.go
0 → 100644
View file @
d6da4342
// 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
core
import
(
"errors"
"github.com/ethereum/go-ethereum/core/types"
)
var
(
// ErrKnownBlock is returned when a block to import is already known locally.
ErrKnownBlock
=
errors
.
New
(
"block already known"
)
// ErrBannedHash is returned if a block to import is on the banned list.
ErrBannedHash
=
errors
.
New
(
"banned hash"
)
// ErrNoGenesis is returned when there is no Genesis Block.
ErrNoGenesis
=
errors
.
New
(
"genesis not found in chain"
)
)
// List of evm-call-message pre-checking errors. All state transition messages will
// be pre-checked before execution. If any invalidation detected, the corresponding
// error should be returned which is defined here.
//
// - If the pre-checking happens in the miner, then the transaction won't be packed.
// - If the pre-checking happens in the block processing procedure, then a "BAD BLOCk"
// error should be emitted.
var
(
// ErrNonceTooLow is returned if the nonce of a transaction is lower than the
// one present in the local chain.
ErrNonceTooLow
=
errors
.
New
(
"nonce too low"
)
// ErrNonceTooHigh is returned if the nonce of a transaction is higher than the
// next one expected based on the local chain.
ErrNonceTooHigh
=
errors
.
New
(
"nonce too high"
)
// ErrGasLimitReached is returned by the gas pool if the amount of gas required
// by a transaction is higher than what's left in the block.
ErrGasLimitReached
=
errors
.
New
(
"gas limit reached"
)
// ErrInsufficientFundsForTransfer is returned if the transaction sender doesn't
// have enough funds for transfer(topmost call only).
ErrInsufficientFundsForTransfer
=
errors
.
New
(
"insufficient funds for transfer"
)
// ErrInsufficientFunds is returned if the total cost of executing a transaction
// is higher than the balance of the user's account.
ErrInsufficientFunds
=
errors
.
New
(
"insufficient funds for gas * price + value"
)
// ErrGasUintOverflow is returned when calculating gas usage.
ErrGasUintOverflow
=
errors
.
New
(
"gas uint64 overflow"
)
// ErrIntrinsicGas is returned if the transaction is specified to use less gas
// than required to start the invocation.
ErrIntrinsicGas
=
errors
.
New
(
"intrinsic gas too low"
)
// ErrTxTypeNotSupported is returned if a transaction is not supported in the
// current network configuration.
ErrTxTypeNotSupported
=
types
.
ErrTxTypeNotSupported
// ErrTipAboveFeeCap is a sanity error to ensure no one is able to specify a
// transaction with a tip higher than the total fee cap.
ErrTipAboveFeeCap
=
errors
.
New
(
"max priority fee per gas higher than max fee per gas"
)
// ErrTipVeryHigh is a sanity error to avoid extremely big numbers specified
// in the tip field.
ErrTipVeryHigh
=
errors
.
New
(
"max priority fee per gas higher than 2^256-1"
)
// ErrFeeCapVeryHigh is a sanity error to avoid extremely big numbers specified
// in the fee cap field.
ErrFeeCapVeryHigh
=
errors
.
New
(
"max fee per gas higher than 2^256-1"
)
// ErrFeeCapTooLow is returned if the transaction fee cap is less than the
// the base fee of the block.
ErrFeeCapTooLow
=
errors
.
New
(
"max fee per gas less than block base fee"
)
// ErrSenderNoEOA is returned if the sender of a transaction is a contract.
ErrSenderNoEOA
=
errors
.
New
(
"sender not an eoa"
)
)
minigeth/core/evm.go
0 → 100644
View file @
d6da4342
// Copyright 2016 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
core
import
(
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
)
// ChainContext supports retrieving headers and consensus parameters from the
// current blockchain to be used during transaction processing.
type
ChainContext
interface
{
// Engine retrieves the chain's consensus engine.
Engine
()
consensus
.
Engine
// GetHeader returns the hash corresponding to their hash.
GetHeader
(
common
.
Hash
,
uint64
)
*
types
.
Header
}
// NewEVMBlockContext creates a new context for use in the EVM.
func
NewEVMBlockContext
(
header
*
types
.
Header
,
chain
ChainContext
,
author
*
common
.
Address
)
vm
.
BlockContext
{
var
(
beneficiary
common
.
Address
baseFee
*
big
.
Int
)
// If we don't have an explicit author (i.e. not mining), extract from the header
if
author
==
nil
{
beneficiary
,
_
=
chain
.
Engine
()
.
Author
(
header
)
// Ignore error, we're past header validation
}
else
{
beneficiary
=
*
author
}
if
header
.
BaseFee
!=
nil
{
baseFee
=
new
(
big
.
Int
)
.
Set
(
header
.
BaseFee
)
}
return
vm
.
BlockContext
{
CanTransfer
:
CanTransfer
,
Transfer
:
Transfer
,
GetHash
:
GetHashFn
(
header
,
chain
),
Coinbase
:
beneficiary
,
BlockNumber
:
new
(
big
.
Int
)
.
Set
(
header
.
Number
),
Time
:
new
(
big
.
Int
)
.
SetUint64
(
header
.
Time
),
Difficulty
:
new
(
big
.
Int
)
.
Set
(
header
.
Difficulty
),
BaseFee
:
baseFee
,
GasLimit
:
header
.
GasLimit
,
}
}
// NewEVMTxContext creates a new transaction context for a single transaction.
func
NewEVMTxContext
(
msg
Message
)
vm
.
TxContext
{
return
vm
.
TxContext
{
Origin
:
msg
.
From
(),
GasPrice
:
new
(
big
.
Int
)
.
Set
(
msg
.
GasPrice
()),
}
}
// GetHashFn returns a GetHashFunc which retrieves header hashes by number
func
GetHashFn
(
ref
*
types
.
Header
,
chain
ChainContext
)
func
(
n
uint64
)
common
.
Hash
{
// Cache will initially contain [refHash.parent],
// Then fill up with [refHash.p, refHash.pp, refHash.ppp, ...]
var
cache
[]
common
.
Hash
return
func
(
n
uint64
)
common
.
Hash
{
// If there's no hash cache yet, make one
if
len
(
cache
)
==
0
{
cache
=
append
(
cache
,
ref
.
ParentHash
)
}
if
idx
:=
ref
.
Number
.
Uint64
()
-
n
-
1
;
idx
<
uint64
(
len
(
cache
))
{
return
cache
[
idx
]
}
// No luck in the cache, but we can start iterating from the last element we already know
lastKnownHash
:=
cache
[
len
(
cache
)
-
1
]
lastKnownNumber
:=
ref
.
Number
.
Uint64
()
-
uint64
(
len
(
cache
))
for
{
header
:=
chain
.
GetHeader
(
lastKnownHash
,
lastKnownNumber
)
if
header
==
nil
{
break
}
cache
=
append
(
cache
,
header
.
ParentHash
)
lastKnownHash
=
header
.
ParentHash
lastKnownNumber
=
header
.
Number
.
Uint64
()
-
1
if
n
==
lastKnownNumber
{
return
lastKnownHash
}
}
return
common
.
Hash
{}
}
}
// CanTransfer checks whether there are enough funds in the address' account to make a transfer.
// This does not take the necessary gas in to account to make the transfer valid.
func
CanTransfer
(
db
vm
.
StateDB
,
addr
common
.
Address
,
amount
*
big
.
Int
)
bool
{
return
db
.
GetBalance
(
addr
)
.
Cmp
(
amount
)
>=
0
}
// Transfer subtracts amount from sender and adds amount to recipient using the given Db
func
Transfer
(
db
vm
.
StateDB
,
sender
,
recipient
common
.
Address
,
amount
*
big
.
Int
)
{
db
.
SubBalance
(
sender
,
amount
)
db
.
AddBalance
(
recipient
,
amount
)
}
minigeth/core/gaspool.go
0 → 100644
View file @
d6da4342
// Copyright 2015 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
core
import
(
"fmt"
"math"
)
// GasPool tracks the amount of gas available during execution of the transactions
// in a block. The zero value is a pool with zero gas available.
type
GasPool
uint64
// AddGas makes gas available for execution.
func
(
gp
*
GasPool
)
AddGas
(
amount
uint64
)
*
GasPool
{
if
uint64
(
*
gp
)
>
math
.
MaxUint64
-
amount
{
panic
(
"gas pool pushed above uint64"
)
}
*
(
*
uint64
)(
gp
)
+=
amount
return
gp
}
// SubGas deducts the given amount from the pool if enough gas is
// available and returns an error otherwise.
func
(
gp
*
GasPool
)
SubGas
(
amount
uint64
)
error
{
if
uint64
(
*
gp
)
<
amount
{
return
ErrGasLimitReached
}
*
(
*
uint64
)(
gp
)
-=
amount
return
nil
}
// Gas returns the amount of gas remaining in the pool.
func
(
gp
*
GasPool
)
Gas
()
uint64
{
return
uint64
(
*
gp
)
}
func
(
gp
*
GasPool
)
String
()
string
{
return
fmt
.
Sprintf
(
"%d"
,
*
gp
)
}
minigeth/core/state_processor.go
View file @
d6da4342
...
...
@@ -18,11 +18,14 @@ package core
import
(
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
/*"fmt"
"math/big"
...
...
@@ -96,7 +99,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
return
receipts
,
allLogs
,
*
usedGas
,
nil
}
/*
func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
func
applyTransaction
(
msg
types
.
Message
,
config
*
params
.
ChainConfig
,
bc
ChainContext
,
author
*
common
.
Address
,
gp
*
GasPool
,
statedb
*
state
.
StateDB
,
blockNumber
*
big
.
Int
,
blockHash
common
.
Hash
,
tx
*
types
.
Transaction
,
usedGas
*
uint64
,
evm
*
vm
.
EVM
)
(
*
types
.
Receipt
,
error
)
{
// Create a new context to be used in the EVM environment.
txContext
:=
NewEVMTxContext
(
msg
)
evm
.
Reset
(
txContext
,
statedb
)
...
...
@@ -155,4 +158,3 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
vmenv
:=
vm
.
NewEVM
(
blockContext
,
vm
.
TxContext
{},
statedb
,
config
,
cfg
)
return
applyTransaction
(
msg
,
config
,
bc
,
author
,
gp
,
statedb
,
header
.
Number
,
header
.
Hash
(),
tx
,
usedGas
,
vmenv
)
}
*/
minigeth/core/state_transition.go
0 → 100644
View file @
d6da4342
// 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
core
import
(
"fmt"
"math"
"math/big"
"github.com/ethereum/go-ethereum/common"
cmath
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)
var
emptyCodeHash
=
crypto
.
Keccak256Hash
(
nil
)
/*
The State Transitioning Model
A state transition is a change made when a transaction is applied to the current world state
The state transitioning model does all the necessary work to work out a valid new state root.
1) Nonce handling
2) Pre pay gas
3) Create a new state object if the recipient is \0*32
4) Value transfer
== If contract creation ==
4a) Attempt to run transaction data
4b) If valid, use result as code for the new state object
== end ==
5) Run Script section
6) Derive new state root
*/
type
StateTransition
struct
{
gp
*
GasPool
msg
Message
gas
uint64
gasPrice
*
big
.
Int
gasFeeCap
*
big
.
Int
gasTipCap
*
big
.
Int
initialGas
uint64
value
*
big
.
Int
data
[]
byte
state
vm
.
StateDB
evm
*
vm
.
EVM
}
// Message represents a message sent to a contract.
type
Message
interface
{
From
()
common
.
Address
To
()
*
common
.
Address
GasPrice
()
*
big
.
Int
GasFeeCap
()
*
big
.
Int
GasTipCap
()
*
big
.
Int
Gas
()
uint64
Value
()
*
big
.
Int
Nonce
()
uint64
IsFake
()
bool
Data
()
[]
byte
AccessList
()
types
.
AccessList
}
// ExecutionResult includes all output after executing given evm
// message no matter the execution itself is successful or not.
type
ExecutionResult
struct
{
UsedGas
uint64
// Total used gas but include the refunded gas
Err
error
// Any error encountered during the execution(listed in core/vm/errors.go)
ReturnData
[]
byte
// Returned data from evm(function result or data supplied with revert opcode)
}
// Unwrap returns the internal evm error which allows us for further
// analysis outside.
func
(
result
*
ExecutionResult
)
Unwrap
()
error
{
return
result
.
Err
}
// Failed returns the indicator whether the execution is successful or not
func
(
result
*
ExecutionResult
)
Failed
()
bool
{
return
result
.
Err
!=
nil
}
// Return is a helper function to help caller distinguish between revert reason
// and function return. Return returns the data after execution if no error occurs.
func
(
result
*
ExecutionResult
)
Return
()
[]
byte
{
if
result
.
Err
!=
nil
{
return
nil
}
return
common
.
CopyBytes
(
result
.
ReturnData
)
}
// Revert returns the concrete revert reason if the execution is aborted by `REVERT`
// opcode. Note the reason can be nil if no data supplied with revert opcode.
func
(
result
*
ExecutionResult
)
Revert
()
[]
byte
{
if
result
.
Err
!=
vm
.
ErrExecutionReverted
{
return
nil
}
return
common
.
CopyBytes
(
result
.
ReturnData
)
}
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
func
IntrinsicGas
(
data
[]
byte
,
accessList
types
.
AccessList
,
isContractCreation
bool
,
isHomestead
,
isEIP2028
bool
)
(
uint64
,
error
)
{
// Set the starting gas for the raw transaction
var
gas
uint64
if
isContractCreation
&&
isHomestead
{
gas
=
params
.
TxGasContractCreation
}
else
{
gas
=
params
.
TxGas
}
// Bump the required gas by the amount of transactional data
if
len
(
data
)
>
0
{
// Zero and non-zero bytes are priced differently
var
nz
uint64
for
_
,
byt
:=
range
data
{
if
byt
!=
0
{
nz
++
}
}
// Make sure we don't exceed uint64 for all data combinations
nonZeroGas
:=
params
.
TxDataNonZeroGasFrontier
if
isEIP2028
{
nonZeroGas
=
params
.
TxDataNonZeroGasEIP2028
}
if
(
math
.
MaxUint64
-
gas
)
/
nonZeroGas
<
nz
{
return
0
,
ErrGasUintOverflow
}
gas
+=
nz
*
nonZeroGas
z
:=
uint64
(
len
(
data
))
-
nz
if
(
math
.
MaxUint64
-
gas
)
/
params
.
TxDataZeroGas
<
z
{
return
0
,
ErrGasUintOverflow
}
gas
+=
z
*
params
.
TxDataZeroGas
}
if
accessList
!=
nil
{
gas
+=
uint64
(
len
(
accessList
))
*
params
.
TxAccessListAddressGas
gas
+=
uint64
(
accessList
.
StorageKeys
())
*
params
.
TxAccessListStorageKeyGas
}
return
gas
,
nil
}
// NewStateTransition initialises and returns a new state transition object.
func
NewStateTransition
(
evm
*
vm
.
EVM
,
msg
Message
,
gp
*
GasPool
)
*
StateTransition
{
return
&
StateTransition
{
gp
:
gp
,
evm
:
evm
,
msg
:
msg
,
gasPrice
:
msg
.
GasPrice
(),
gasFeeCap
:
msg
.
GasFeeCap
(),
gasTipCap
:
msg
.
GasTipCap
(),
value
:
msg
.
Value
(),
data
:
msg
.
Data
(),
state
:
evm
.
StateDB
,
}
}
// ApplyMessage computes the new state by applying the given message
// against the old state within the environment.
//
// ApplyMessage returns the bytes returned by any EVM execution (if it took place),
// the gas used (which includes gas refunds) and an error if it failed. An error always
// indicates a core error meaning that the message would always fail for that particular
// state and would never be accepted within a block.
func
ApplyMessage
(
evm
*
vm
.
EVM
,
msg
Message
,
gp
*
GasPool
)
(
*
ExecutionResult
,
error
)
{
return
NewStateTransition
(
evm
,
msg
,
gp
)
.
TransitionDb
()
}
// to returns the recipient of the message.
func
(
st
*
StateTransition
)
to
()
common
.
Address
{
if
st
.
msg
==
nil
||
st
.
msg
.
To
()
==
nil
/* contract creation */
{
return
common
.
Address
{}
}
return
*
st
.
msg
.
To
()
}
func
(
st
*
StateTransition
)
buyGas
()
error
{
mgval
:=
new
(
big
.
Int
)
.
SetUint64
(
st
.
msg
.
Gas
())
mgval
=
mgval
.
Mul
(
mgval
,
st
.
gasPrice
)
balanceCheck
:=
mgval
if
st
.
gasFeeCap
!=
nil
{
balanceCheck
=
new
(
big
.
Int
)
.
SetUint64
(
st
.
msg
.
Gas
())
balanceCheck
=
balanceCheck
.
Mul
(
balanceCheck
,
st
.
gasFeeCap
)
balanceCheck
.
Add
(
balanceCheck
,
st
.
value
)
}
if
have
,
want
:=
st
.
state
.
GetBalance
(
st
.
msg
.
From
()),
balanceCheck
;
have
.
Cmp
(
want
)
<
0
{
return
fmt
.
Errorf
(
"%w: address %v have %v want %v"
,
ErrInsufficientFunds
,
st
.
msg
.
From
()
.
Hex
(),
have
,
want
)
}
if
err
:=
st
.
gp
.
SubGas
(
st
.
msg
.
Gas
());
err
!=
nil
{
return
err
}
st
.
gas
+=
st
.
msg
.
Gas
()
st
.
initialGas
=
st
.
msg
.
Gas
()
st
.
state
.
SubBalance
(
st
.
msg
.
From
(),
mgval
)
return
nil
}
func
(
st
*
StateTransition
)
preCheck
()
error
{
// Only check transactions that are not fake
if
!
st
.
msg
.
IsFake
()
{
// Make sure this transaction's nonce is correct.
stNonce
:=
st
.
state
.
GetNonce
(
st
.
msg
.
From
())
if
msgNonce
:=
st
.
msg
.
Nonce
();
stNonce
<
msgNonce
{
return
fmt
.
Errorf
(
"%w: address %v, tx: %d state: %d"
,
ErrNonceTooHigh
,
st
.
msg
.
From
()
.
Hex
(),
msgNonce
,
stNonce
)
}
else
if
stNonce
>
msgNonce
{
return
fmt
.
Errorf
(
"%w: address %v, tx: %d state: %d"
,
ErrNonceTooLow
,
st
.
msg
.
From
()
.
Hex
(),
msgNonce
,
stNonce
)
}
// Make sure the sender is an EOA
if
codeHash
:=
st
.
state
.
GetCodeHash
(
st
.
msg
.
From
());
codeHash
!=
emptyCodeHash
&&
codeHash
!=
(
common
.
Hash
{})
{
return
fmt
.
Errorf
(
"%w: address %v, codehash: %s"
,
ErrSenderNoEOA
,
st
.
msg
.
From
()
.
Hex
(),
codeHash
)
}
}
// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
if
st
.
evm
.
ChainConfig
()
.
IsLondon
(
st
.
evm
.
Context
.
BlockNumber
)
{
// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
if
!
st
.
evm
.
Config
.
NoBaseFee
||
st
.
gasFeeCap
.
BitLen
()
>
0
||
st
.
gasTipCap
.
BitLen
()
>
0
{
if
l
:=
st
.
gasFeeCap
.
BitLen
();
l
>
256
{
return
fmt
.
Errorf
(
"%w: address %v, maxFeePerGas bit length: %d"
,
ErrFeeCapVeryHigh
,
st
.
msg
.
From
()
.
Hex
(),
l
)
}
if
l
:=
st
.
gasTipCap
.
BitLen
();
l
>
256
{
return
fmt
.
Errorf
(
"%w: address %v, maxPriorityFeePerGas bit length: %d"
,
ErrTipVeryHigh
,
st
.
msg
.
From
()
.
Hex
(),
l
)
}
if
st
.
gasFeeCap
.
Cmp
(
st
.
gasTipCap
)
<
0
{
return
fmt
.
Errorf
(
"%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s"
,
ErrTipAboveFeeCap
,
st
.
msg
.
From
()
.
Hex
(),
st
.
gasTipCap
,
st
.
gasFeeCap
)
}
// This will panic if baseFee is nil, but basefee presence is verified
// as part of header validation.
if
st
.
gasFeeCap
.
Cmp
(
st
.
evm
.
Context
.
BaseFee
)
<
0
{
return
fmt
.
Errorf
(
"%w: address %v, maxFeePerGas: %s baseFee: %s"
,
ErrFeeCapTooLow
,
st
.
msg
.
From
()
.
Hex
(),
st
.
gasFeeCap
,
st
.
evm
.
Context
.
BaseFee
)
}
}
}
return
st
.
buyGas
()
}
// TransitionDb will transition the state by applying the current message and
// returning the evm execution result with following fields.
//
// - used gas:
// total gas used (including gas being refunded)
// - returndata:
// the returned data from evm
// - concrete execution error:
// various **EVM** error which aborts the execution,
// e.g. ErrOutOfGas, ErrExecutionReverted
//
// However if any consensus issue encountered, return the error directly with
// nil evm execution result.
func
(
st
*
StateTransition
)
TransitionDb
()
(
*
ExecutionResult
,
error
)
{
// First check this message satisfies all consensus rules before
// applying the message. The rules include these clauses
//
// 1. the nonce of the message caller is correct
// 2. caller has enough balance to cover transaction fee(gaslimit * gasprice)
// 3. the amount of gas required is available in the block
// 4. the purchased gas is enough to cover intrinsic usage
// 5. there is no overflow when calculating intrinsic gas
// 6. caller has enough balance to cover asset transfer for **topmost** call
// Check clauses 1-3, buy gas if everything is correct
if
err
:=
st
.
preCheck
();
err
!=
nil
{
return
nil
,
err
}
msg
:=
st
.
msg
sender
:=
vm
.
AccountRef
(
msg
.
From
())
homestead
:=
st
.
evm
.
ChainConfig
()
.
IsHomestead
(
st
.
evm
.
Context
.
BlockNumber
)
istanbul
:=
st
.
evm
.
ChainConfig
()
.
IsIstanbul
(
st
.
evm
.
Context
.
BlockNumber
)
london
:=
st
.
evm
.
ChainConfig
()
.
IsLondon
(
st
.
evm
.
Context
.
BlockNumber
)
contractCreation
:=
msg
.
To
()
==
nil
// Check clauses 4-5, subtract intrinsic gas if everything is correct
gas
,
err
:=
IntrinsicGas
(
st
.
data
,
st
.
msg
.
AccessList
(),
contractCreation
,
homestead
,
istanbul
)
if
err
!=
nil
{
return
nil
,
err
}
if
st
.
gas
<
gas
{
return
nil
,
fmt
.
Errorf
(
"%w: have %d, want %d"
,
ErrIntrinsicGas
,
st
.
gas
,
gas
)
}
st
.
gas
-=
gas
// Check clause 6
if
msg
.
Value
()
.
Sign
()
>
0
&&
!
st
.
evm
.
Context
.
CanTransfer
(
st
.
state
,
msg
.
From
(),
msg
.
Value
())
{
return
nil
,
fmt
.
Errorf
(
"%w: address %v"
,
ErrInsufficientFundsForTransfer
,
msg
.
From
()
.
Hex
())
}
// Set up the initial access list.
if
rules
:=
st
.
evm
.
ChainConfig
()
.
Rules
(
st
.
evm
.
Context
.
BlockNumber
);
rules
.
IsBerlin
{
st
.
state
.
PrepareAccessList
(
msg
.
From
(),
msg
.
To
(),
vm
.
ActivePrecompiles
(
rules
),
msg
.
AccessList
())
}
var
(
ret
[]
byte
vmerr
error
// vm errors do not effect consensus and are therefore not assigned to err
)
if
contractCreation
{
ret
,
_
,
st
.
gas
,
vmerr
=
st
.
evm
.
Create
(
sender
,
st
.
data
,
st
.
gas
,
st
.
value
)
}
else
{
// Increment the nonce for the next transaction
st
.
state
.
SetNonce
(
msg
.
From
(),
st
.
state
.
GetNonce
(
sender
.
Address
())
+
1
)
ret
,
st
.
gas
,
vmerr
=
st
.
evm
.
Call
(
sender
,
st
.
to
(),
st
.
data
,
st
.
gas
,
st
.
value
)
}
if
!
london
{
// Before EIP-3529: refunds were capped to gasUsed / 2
st
.
refundGas
(
params
.
RefundQuotient
)
}
else
{
// After EIP-3529: refunds are capped to gasUsed / 5
st
.
refundGas
(
params
.
RefundQuotientEIP3529
)
}
effectiveTip
:=
st
.
gasPrice
if
london
{
effectiveTip
=
cmath
.
BigMin
(
st
.
gasTipCap
,
new
(
big
.
Int
)
.
Sub
(
st
.
gasFeeCap
,
st
.
evm
.
Context
.
BaseFee
))
}
st
.
state
.
AddBalance
(
st
.
evm
.
Context
.
Coinbase
,
new
(
big
.
Int
)
.
Mul
(
new
(
big
.
Int
)
.
SetUint64
(
st
.
gasUsed
()),
effectiveTip
))
return
&
ExecutionResult
{
UsedGas
:
st
.
gasUsed
(),
Err
:
vmerr
,
ReturnData
:
ret
,
},
nil
}
func
(
st
*
StateTransition
)
refundGas
(
refundQuotient
uint64
)
{
// Apply refund counter, capped to a refund quotient
refund
:=
st
.
gasUsed
()
/
refundQuotient
if
refund
>
st
.
state
.
GetRefund
()
{
refund
=
st
.
state
.
GetRefund
()
}
st
.
gas
+=
refund
// Return ETH for remaining gas, exchanged at the original rate.
remaining
:=
new
(
big
.
Int
)
.
Mul
(
new
(
big
.
Int
)
.
SetUint64
(
st
.
gas
),
st
.
gasPrice
)
st
.
state
.
AddBalance
(
st
.
msg
.
From
(),
remaining
)
// Also return remaining gas to the block gas counter so it is
// available for the next transaction.
st
.
gp
.
AddGas
(
st
.
gas
)
}
// gasUsed returns the amount of gas used up by the state transition.
func
(
st
*
StateTransition
)
gasUsed
()
uint64
{
return
st
.
initialGas
-
st
.
gas
}
minigeth/core/vm/interpreter.go
View file @
d6da4342
...
...
@@ -18,13 +18,34 @@ package vm
import
(
"hash"
"math/big"
"sync/atomic"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
//"github.com/ethereum/go-ethereum/log"
)
// **** stub Tracer ****
type
Tracer
struct
{}
// CaptureStart implements the Tracer interface to initialize the tracing operation.
func
(
jst
*
Tracer
)
CaptureStart
(
env
*
EVM
,
from
common
.
Address
,
to
common
.
Address
,
create
bool
,
input
[]
byte
,
gas
uint64
,
value
*
big
.
Int
)
{
}
// CaptureState implements the Tracer interface to trace a single step of VM execution.
func
(
jst
*
Tracer
)
CaptureState
(
env
*
EVM
,
pc
uint64
,
op
OpCode
,
gas
,
cost
uint64
,
scope
*
ScopeContext
,
rData
[]
byte
,
depth
int
,
err
error
)
{
}
// CaptureFault implements the Tracer interface to trace an execution fault
func
(
jst
*
Tracer
)
CaptureFault
(
env
*
EVM
,
pc
uint64
,
op
OpCode
,
gas
,
cost
uint64
,
scope
*
ScopeContext
,
depth
int
,
err
error
)
{
}
// CaptureEnd is called after the call finishes to finalize the tracing.
func
(
jst
*
Tracer
)
CaptureEnd
(
output
[]
byte
,
gasUsed
uint64
,
t
time
.
Duration
,
err
error
)
{
}
// Config are the configuration options for the Interpreter
type
Config
struct
{
Debug
bool
// Enables debugging
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment