go-ethereum v0.7.10 - core
Module - Source Code Analysis
In this project I dive into the core module of the official go-ethereumv0.7.10 and try
to give a thorough explanation on all code that's included in this module.
The code can alternatively be explored through:
https://pkg.go.dev/github.com/georzaza/go-ethereum-v0.7.10_official
Please note that both this repository and the above link contain the official code
along with comments that I've written in order to help myself get through with
this project. The original codebase contained very-very limited comment sections.
Any inner links in this file point just below the definition/signature of
a data structure/function. Remember to scroll up just a bit after clicking
on a link.
If you are interested in analyzing any of the other modules you might find useful
the folder georzaza_scripts
and/or the file georzaza_output
, which examine files'
similarity across all modules of this go-ethereum version.
1. Description
The core module is the implementation of the basic logic of Ethereum.
What is shown below is a list of all files the core
contains with a
short description.
With very few exceptions, each file implements a ... core idea of Ethereum.
- core/types/block.go
Block type definition along with functions on how to create a block,
set it's header, find a transaction in a block, set it's uncles and more.
- core/types/bloom9.go
Bloom definition. The bloom is used in order to save space while storing
a transaction receipt's log fields.
- core/types/common.go
Contains the definition of 2 interfaces, namely BlockProcessor and Broadcaster
which are implemented by the ChainManager and TxPool accordingly.
- core/types/receipt.go
Contains the definition of a receipt and functions which may be used on a receipt object.
- core/types/transaction.go
Contains the definition of a transaction. It's important to note that in this file
functions are defined which either sign a transaction or get it's public key.
- core/block_manager.go
Aside from the BlockManager, this file also contains the definition of a very
important interface, 'EthManager', which is implemented by the 'Ethereum' object,
defined in the file ethereum.go. The BlockManager is responsible for:
- Applying the transactions of a block.
- Validating the block.
- Calculating the new total difficulty and the miner's reward.
- core/chain_manager.go
The ChainManager as it's name suggests is responsible for:
- Adding a block to the chain. Note however that the BlockManager is the one
responsible for applying the transactions. After adding a block, that block
will also be saved in the main db.
- Reseting the chain. This means that through the ChainManager we can reset
the chain to the point where it will include only the genesis block.
- Providing ways to determine whether a block is in the chain or not.
- Calculating the total difficulty.
- Inserting a chain of blocks to the current chain. (function
InsertChain)
This file also includes the definition of the function
CalcDifficulty which calculates
the difficulty of a block (which is different than the total difficulty of the chain).
- core/dagger.go
The Dagger consensus model. Dagger is a memory-hard proof of work model
based on directed acyclic graphs. Memory hardness refers to the concept that
computing a valid proof of work should require not only a large number of
computations, but also a large amount of memory.
- core/error.go
Contains the definition of error types that might come up when either
validating a block, applying it's transactions or inserting it into the chain.
- core/events.go
Containts the definition of events fired when:
- a transaction is added to the transaction pool
- a transaction has been processed
- a block has been imported to the chain.
- execution.go
Contains the definition of an Execution type alongside the
most basic (inner) function
through which all code execution happens.
The EVM creates and calls an Execution's
object functions in order to execute code.
- core/transaction_pool.go
Contains the definition of TxPool. A TxPool object
is used to group transactions.
Validation of transactions happens through this object's methods.
-
core/vm_env.go
Definition of the EVM. The EVM implements the Environment interface,
defined in the file vm/environment.go and works closely with the
Execution
model in order to handle smart contract deployment and code execution.
The below image shows in detail how most of the above concepts are glued together
with the EVM:
1. Package types
1.1 block.go
1.1.1 Data structures
type BlockInfo struct {
Number uint64
Hash []byte
Parent []byte
TD *big.Int
}
A 'compact' way of representing a block is by the use of the
BlockInfo type
- Number: The number of the block
- Hash: The hash of the block
- Parent: The parent of the block.
- TD: used by the package core to store the total difficulty
of the chain up to and including a block.
More specifically:
$Block.TD = Block.parent.TD + Block.difficulty + \sum_{u;\epsilon;Uncles} {u.difficulty}$
type Block struct {
PrevHash ethutil.Bytes
Uncles Blocks
UncleSha []byte
Coinbase []byte
state *state.StateDB
Difficulty *big.Int
Time int64
Number *big.Int
GasLimit *big.Int
GasUsed *big.Int
Extra string
Nonce ethutil.Bytes
transactions Transactions
receipts Receipts
TxSha, ReceiptSha []byte
LogsBloom []byte
Reward *big.Int
}
A Block
type is the main type used to represent a block.
- PrevHash: The Keccak 256-bit hash of the parent block’s header
- Uncles : The uncles of the Block.
- UncleSha: The Keccak 256-bit hash of the uncles of the Block.
- CoinBase: The address of the beneficiary.
- beneficiary: The 160-bit address to which all fees collected from
the successful mining of this block are transferred to (miner's address).
- state: The Keccak 256-bit hash of the root node of the state trie,
after all transactions are executed
- Difficulty : Difficulty of the current block.
- Time: Creation time of the Block.
- Number: The number of the Block. This is equal to the number of
ancestor blocks.
- GasLimit: The maximum gas limit all the transactions inside this
Block are allowed to consume.
- GasUsed: The total gas used by the transactions of the Block.
- Extra: An arbitrary byte array containing data relevant to this block.
According to the Ethereum yellow paper this should be 32 bytes or less.
- Nonce: The Block nonce. This is what miners keep changing to compute
a solution to PoW.
- transactions: List of transactions and/or contracts to be created
included in this Block.
- receipts: The receipts of the transactions
- TxSha: The Keccak 256-bit hash of the root node of the transactions
trie of the block
- ReceiptSha: The Keccak 256-bit hash of the root node of the receipts
trie of the block.
- LogsBloom: The Bloom filter composed from indexable information
(logger address and log
topics) contained in each log entry from
the receipt of each transaction in the transactions list.
- Reward: The reward of the beneficiary (miner)
Notes about uncles: "In case of proof-of-work mining, there are many miners
trying to mine the same set of transactions at the same time. Since the block
mining time is very short (about 15 sec. in case of ethereum) there is a
possibility,that more than one blocks are mined within a very short interval.
The block mined first is added to the main chain but the effort of miner who
mined the other block in not simply let off. These competing blocks are called
orphaned blocks.
According to ethereum beige paper, " An uncle is a block whose parent is equal
to the current block’s parent’s parent." The purpose of uncles is to help reward
miners for including these orphaned blocks. The uncles that miners include must
be “valid,” meaning within the sixth generation or smaller of the present block.
After six children, stale orphaned blocks can no longer be referenced.
Uncle blocks receive a smaller reward than a full block. Nonetheless, there’s
still some incentive for miners to include these orphaned blocks and reap a reward."
Source: https://medium.com/@preethikasireddy/how-does-ethereum-work-anyway-22d1df506369
type Blocks []*Block
Blocks grouping type.
type BlockBy func(b1, b2 *Block) bool
type blockSorter struct {
blocks Blocks
by func(b1, b2 *Block) bool
}
A BlockBy
type along with
a blockSorter
type are used as a sorting mechanism
(which makes use of the sort.Sort function:
https://pkg.go.dev/sort#Sort ).
Note that the blockSorter type is not exported (does not start with a capital
letter),
so it's only visible to the current file.
- blocks: the blocks to be sorted (can be any number of Blocks).
- by: The sorting function to be used between two Blocks of the blockSorter.
Although internally a BlockBy object is assigned to this field, note
that the definition allows any function that is matching the function
signature of 'by') to be assigned to this field.
1.1.2 Functions
func (bi *BlockInfo) RlpDecode(data []byte)
RlpDecode
sets the caller's
(BlockInfo)
fields to the RLP-decoded parts of the 'data' parameter.
To do so, data is converted to an ethutil.Value object and the RLP-decoding operation happens on the Value object.
func (bi *BlockInfo) RlpEncode() []byte
RlpEncode
returns the rlp-encoding of a BlockInfo
object (by calling the function Encode defined in ethutil/rlp.go)
func (self Blocks) AsSet() ethutil.UniqueSet
AsSet
returns the Blocks that the caller consists of as an ethutil.UniqueSet object.
The elements of the returned set will be the hashes of these Blocks (only a
Blocks object can call this function).
func (self BlockBy) Sort(blocks Blocks)
Sort
sorts Blocks.
This function creates a
blockSorter object,
assigns the caller (BlockBy)
object to the blockSorter's 'by' field
and the param 'blocks' object to the
blockSorter's 'blocks' field, and then calls the sort.Sort function
(https://pkg.go.dev/sort#Sort) by passing to it the created blockSorter object.
The sort.Sort function makes use of Len, Less, Swap functions to sort the objects,
all defined below.
func (self blockSorter) Len() int
Len
returns the number of Blocks that a
blockSorter
object consists of.
func (self blockSorter) Swap(i, j int)
Swap
swaps two Blocks of a
blockSorter
object.
func (self blockSorter) Less(i, j int)
Less. For any 2 Blocks
that the caller (blockSorter) consists of,
denoted as i, j, this function returns
true if Block i is less than j. To determine
whether i is less than j, a
BlockBy object is used.
func Number(b1, b2 *Block) bool
Number
returns true if the block number of b1 is less than b2, false otherwise.
func NewBlockFromBytes(raw []byte) *Block
NewBlockFromBytes
creates a new Block from the 'raw' bytes param and returns it.
These bytes however should be the bytes representation of the result
of the RLP-encoding of a Block.
func NewBlockFromRlpValue(rlpValue *ethutil.Value) *Block
NewBlockFromRlpValue
creates a new Block from the 'rlpValue' param.
To do so, this function calls
the Block.RlpValueDecode
function. As described in the latter,
only the Block's header, transactions
and uncles fields are derived from the rlpValue object.
func CreateBlock(root interface{}, prevHash []byte, base []byte, Difficulty *big.Int, Nonce []byte, extra string) *Block
CreateBlock
creates a Block and returns it. See the Block
data structure for an explanation of the fields used.
The root parameter is the root of the Block's state trie.
The Block created will be created at the current Unix time.
Notice that there are no transactions and receipts passed as arguments
to this function, aka these are not set.
func (block *Block) Hash() ethutil.Bytes
Hash
returns the block's hash. To do so, these are the steps followed:
- block's header is first cast to an ethutil.Value object
- the Encode function is called upon the casted object.
- the keccak-256 hash of the returned object of the step 2 is returned.
func (block *Block) HashNoNonce() []byte
HashNoNonce
returns the hash of an object that is almost the same as a Block. The differences are:
- The object to be hashed contains only the uncles hash.
- The object to be hashed contains the root of the state and not the state as a whole.
- The object to be hashed contains only the TxSha and not the receipts.
- The object to be hashed contains only the ReceiptSha and not the transactions.
- The object to be hashed does not contain the Reward of the miner.
Note: The object to be hashed if appended with the Nonce field of the Block
will comprise the Block's header.
func (block *Block) State() *state.StateDB
State
returns the state of the Block. (not just the root)
func (block *Block) Transactions() Transactions
Transactions
returns the transactions of the block.
func (block *Block) CalcGasLimit(parent *Block) *big.Int
CalcGasLimit
calculates the gas limit.
If the Block passed as a parameter (aka the parent)
is the genesis block the gas limit is set to $10^6$.
Otherwise the gas limit will be:
$1023 \cdot parent.GasLimit + parent.GasUsed \cdot \frac{6}{5}$.
The minimum gas limit is set to $125000$ Wei.
func (block *Block) BlockInfo() BlockInfo
BlockInfo
returns the BlockInfo
representation of a Block.
func (self *Block) GetTransaction(hash []byte) *Transaction
GetTransaction
searches for a transaction in the current Block by comparing the hash of all
the transactions in the block to the 'hash' parameter.
Returns the block's matching transaction, or nil if there is no match.
func (block *Block) Sync()
Sync
syncs the block's state and contract respectively. For more, see the state package.
func (block *Block) Undo()
Undo
resets the block's state to nil.
func (block *Block) rlpReceipts() interface{}
rlpReceipts
is an inner function that returns the receipts as a string.
This function is used to derive the ReceiptSha of the receipts.
Although defined, this function is never used in this go-ethereum version.
func (block *Block) rlpUncles() interface{}
rlpUncles returns the uncles
as a string.
This function is used to derive the UncleSha of the uncles.
Gets called by the
Block.SetUncles,
Block.Value and
Block.RlpData functions.
func (block *Block) SetUncles(uncles []*Block)
SetUncles
sets the uncles of Block to the parameter 'uncles'.
This function is also
called by the CreateBlock
function. Also sets the UncleSha of
the Block based on the provided parameter.
To do so, the inner function rlpUncles
is called.
func (self *Block) SetReceipts(receipts Receipts)
SetReceipts
sets the receipts of this block to the parameter 'receipts'.
Also calculates and sets the LogsBloom field of the block which
is derived by the receipts.
func (self *Block) SetTransactions(txs Transactions)
SetTransactions
sets the transactions of a Block to the parameter 'transactions'.
Also calculates and sets the TxSha field which is derived by the transactions.
func (block *Block) Value() *ethutil.Value
Value
casts a block to an ethutil.Value object containing the header,
the transactions and the uncles of the block and then returns it.
func (block *Block) RlpEncode() []byte
RlpEncode
calls the
Value
function on the current Block and then rlp-encodes the Block.
The rlp-encodable fields of a Block are it's header, transactions and uncles.
func (block *Block) RlpDecode(data []byte)
RlpDecode
RLP-decodes a Block.
To do so, a new ethutil.Value object is created from the
data param and then
the function RlpValueDecode(data)
is called on the current Block.
- data represents the rlp-encodable fields of this block and can be
obtained through the function
RlpData.
func (block *Block) RlpValueDecode(decoder *ethutil.Value)
RlpValueDecode
RLP-decodes the rlp-encodable fields of a Block, aka the header, transactions and uncles.
- decoder: The above fields of this Block after having been cast to an ethutil.Value object.
func (self *Block) setHeader(header *ethutil.Value)
setHeader
is an inner function that sets the header of this block,
given an ethutil.Value object that contains that information.
func NewUncleBlockFromValue(header *ethutil.Value) *Block
NewUncleBlockFromValue
creates and sets the uncle of a block based
on an ethutil.Value object that contains that information.
- header: an ethutil.Value object containing the header of the uncle block.
The header of the uncle Block (and any Block) contains those fields:
PrevHash, UncleSha, Coinbase, state, TxSha, ReceiptSha, LogsBloom,
Difficulty, Number, GasLimit, GasUsed, Time, Extra, Nonce.
See also the HashNoNonce
function for details about these fields.
func (block *Block) Trie() *trie.Trie
Trie
returns the block's state trie
func (block *Block) Root() interface{}
Root
returns the block's state root
func (block *Block) Diff() *big.Int
Diff
returns the block's difficulty.
func (self *Block) Receipts() []*Receipt
Receipts
returns the block's receipts.
func (block *Block) miningHeader() []interface{}
miningHeader
returns an object that is almost the same as a Block. The differences are:
- The Block struct also contains the uncles as a slice of Blocks and not only the uncles hash.
- The Block struct contains the state object as a whole and not the root of the state.
- The Block struct contains the receipts and not only the TxSha
- The Block struct contains the transactions and not only the ReceiptSha
- The Block struct contains the Reward to be given to the miner.
The object returned, if appended with the Nonce field of the Block is the Block's header.
func (block *Block) header() []interface{}
header
returns the header of the Block. See the function
miningHeader
for a detailed explanation.
func (block *Block) String() string
String
returns the string representation of the block.
func (self *Block) Size() ethutil.StorageSize
Size
returns a float64 object representing the size of storage needed to save this
block's rlp-encoding.
The rlp-encodable fields of a Block are it's header, transactions and uncles.
func (self *Block) RlpData() interface{}
RlpData
returns an object containing this block's rlp-encodable fields.
The rlp-encodable fields of a Block are it's header, transactions and uncles.
(this is also the order in which the returned object contains them).
func (self *Block) N() []byte
N
returns the Nonce field of the block.
1.2 common.go
Only contains the definition of 2 interfaces.
type BlockProcessor interface {
Process(*Block) (*big.Int, state.Messages, error)
}
Any type that implements the
BlockProcessor interface must
also implement the Process
function which is called upon a Block and calculates
and returns in that order:
the total difficulty of the block, the messages of the
block (aka the transactions) and/or an error.
In case of an error, the values
returned by the function Process for the td and messages are nil.
In case of no errors, the error value returned by the Process function is nil.
Only a ChainManager
object implements this interface.
type Broadcaster interface {
Broadcast(wire.MsgType, []interface{})
}
Any object that implements the Broadcaster interface must also implement the function 'Broadcast',
which is used to broadcast messages of a given type to a list of recipients.
The type of the message to
be broadcasted, wire.MsgType, is a single byte and is defined in the package
wire (file wire/messaging.go).
Only a TxPool
object implements this interface.
1.3 derive_sha.go
type DerivableList interface {
Len() int
GetRlp(i int) []byte
}
Any object that implements the
DerivableList interface can then
call the function DeriveSha.
Examples of objects that implement this interface are the
Receipt and the
Transaction objects.
- Len(): returns the number of the elements of the object
that implements this interface.
- GetRlp(i int): returns the RLP-encoding of i-th element of the object
that implements this interface.
func DeriveSha(list DerivableList) []byte
DerivableList contructs a trie based on
the list parameter and returns the root hash of the trie.
Examples of objects that make use of this function are the
Receipt and
Transaction objects.
1.4 transaction.go
1.4.1 Data structures
type Transaction struct {
nonce uint64
recipient []byte
value *big.Int
gas *big.Int
gasPrice *big.Int
data []byte
v byte
r, s []byte
}
Definition of a Transaction object.
A Transaction object implements the Message
interface.
- Nonce: A value equal to the number of transactions that originated from
this address or, in the case of accounts with associated code, the number
of contract-creations made by this account.
- recipient: The 160-bit address of the transaction's recipient or,
for a contract creation transaction, nil.
- value: This is equal to the number of Wei to be transferred to the
transaction's recipient or, in the case of contract creation, as an
endowment to the newly created account.
- gas: The gas limit equal to the maximum amount of gas that should be
used when executing this transaction.
- gasPrice: This is equal to the number of Wei to be paid per unit of gas for
all computation costs incurred as a result of the execution of this
transaction.
- data: An unlimited size byte array specifying the input data of the
transaction.
The first 4 bytes of this field specify which function to call
when the transaction
will execute by using the hash of the function's name
to be called and it's arguments.
The rest of the data field are the arguments
passed to the function.
If the data field is empty, it means a transaction is for a payment and not
an execution of the contract.
- v, r, s: Values corresponding to the ECDSA digital signature of
the transaction and used to determine
the originating Externally Owned Account.
type Transactions []*Transaction
The Transactions
data type is defined as a means to
- sort Transactions and
- derive the root hash of a trie consisting of a list of transactions.
type TxByNonce struct{ Transactions }
the TxByNonce data type is used
for to perform comparison operations on Transaction objects.
1.4.2 Functions
func IsContractAddr(addr []byte) bool
IsContractAddr
returns true if the provided 'addr' has a length of 0, false otherwise.
func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction
NewContractCreationTx
creates and returns a new Transaction which represents the creation of a contract.
The Transaction's 'recipient' field will be set to nil and the Transaction's
'data' field will be set to the 'script' parameter.
All other Transaction fields will be set to the corresponing parameters
passed to this function
(except of course for the fields nonce,v,r,s which are not set)
func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction
NewTransactionMessage
creates and returns a new Transaction.
All Transaction fields will be set to the corresponing parameters passed to this function
(except of course for the fields nonce,v,r,s which are not set)
func NewTransactionFromBytes(data []byte) *Transaction
NewTransactionFromBytes
creates and returns a new Transaction based on the 'data' parameter.
The latter should be a valid rlp-encoding of the Transaction object to be created.
(The 'data' param is converted to an ethutil.Value object first and then gets decoded)
func NewTransactionFromValue(val *ethutil.Value) *Transaction
NewTransactionFromValue
creates and returns a new Transaction based on the 'val' parameter.
The latter should be a valid rlp-encoding - of the Transaction object to be created
- that has been cast
to an ethutil.Value object.
func (tx *Transaction) Hash() []byte
Hash
returns the hash of the caller. The hash will be the Kecchak-256 hash of
these Transaction fields:
nonce, gasPrice, gas, recipient, value, data.
This function is implemented as part of the
Message
interface
func (self *Transaction) Data() []byte
Data
returns the 'data' field of the caller.
func (self *Transaction) Gas() *big.Int
Gas
returns the 'gas' field of the caller.
This function is implemented as part of the
Message
interface
func (self *Transaction) GasPrice() *big.Int
GasPrice
returns the 'gasPrice' field of the caller.
This function is implemented as part of the
Message
interface
func (self *Transaction) Value() *big.Int
Value
returns the 'value' field of the caller.
This function is implemented as part of the
Message
interface
func (self *Transaction) Nonce() uint64
Nonce
returns the 'nonce' field of the caller.
This function is implemented as part of the
Message
interface
func (self *Transaction) SetNonce(nonce uint64)
SetNonce
assigns the 'nonce' param to the caller's nonce field.
func (self *Transaction) From() []byte
From
returns the 'sender' of the caller.
This function is implemented as part of the
Message
interface
func (self *Transaction) To() []byte
To
returns the 'recipient' field of the caller.
This function is implemented as part of the
Message
interface
func (tx *Transaction) Curve() (v byte, r []byte, s []byte)
Curve
returns v, r, s of the Transaction. r and s are left-padded to 32 bytes.
For more, see the function ethutil.leftPadBytes
func (tx *Transaction) Signature(key []byte) []byte
Signature
calculates and returns the signature of the hash of a transaction with the param key.
The signature used to be obtained through the
github.com/obscuren/secp256k1-go package repo
but this package no longer exists. One may now use the function Sign from:
https://github.com/ethereum/go-ethereum/blob/master/crypto/secp256k1/secp256.go
func (tx *Transaction) PublicKey() []byte
PublicKey
retrieves and returns the public key of the transaction.
The public key used to be obtained through the github.com/obscuren/secp256k1-go
package repo but this package no longer exists.
One may now use the function RecoverPubKey from:
https://github.com/ethereum/go-ethereum/blob/master/crypto/secp256k1/secp256.go
func (tx *Transaction) Sender() []byte
Sender
returns the sender of the transaction. To do so, the public key of the transaction
is first
retrieved through the function PublicKey.
If the public key passes validation then the last 12
bytes of the public key
are returned (aka the sender address).
func (tx *Transaction) Sign(privk []byte) error
Sign signes the transaction.
To do so, the function Signature
is called (which makes use of a non-existent package, refer to it for more).
After the transaction has been signed the r,s,v fields of the Transaction are set
to the signatures appropriate fields.
r is set to the first 32 bytes of thTransaction.e signature.
s is set to the 32-th up to and including the 63-th bytes of the signature.
v is set to the sum of the last bit of the transaction and the number 27.
func (tx *Transaction) RlpData() interface{}
RlpData
returns the rlp-encodable fields of the caller
(all fields of a Transaction object).
func (tx *Transaction) RlpValue() *ethutil.Value
RlpValue
casts and returns the caller to an ethutil.Value object.
func (tx *Transaction) RlpEncode() []byte
RlpEncode returns the
rlp-encoding of the cast of the caller object to an ethutil.Value object.
The cast is done through the
RlpValue function.
func (tx *Transaction) RlpDecode(data []byte)
RlpDecode
sets the caller's fields equal to the rlp-decoding of the 'data' parameter.
The data param must be a valid bytes representation of a
Transaction
that has been cast to an ethutil.Value object.
func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value)
RlpValueDecode
sets the caller's fields equal to the rlp-decoding of the 'decoder'.
The decoder must be a valid bytes representation of a
Transaction
that has been cast to an ethutil.Value object.
func (tx *Transaction) String() string
String
returns the string representation of the caller.
func (self Transactions) RlpData() interface{}
RlpData
returns the rlp-encodable fields of all the
Transaction objects
that the caller consists of.
func (s Transactions) Len() int
Len
returns the number of the Transaction objects that the caller consists of.
This function, along with the GetRlp function
are implemented as parts of the DerivableList interface
in order to be able to call the DeriveSha function on
a Transactions object, which would return the hash
of the root of the trie consisted of
the Transaction objects that are included in the Transactions object.
func (s Transactions) GetRlp(i int) []byte
GetRlp
returns the rlp-encoding of the i-th Transaction of the caller.
This function, along with the Len function
are implemented as parts of the DerivableList interface
in order to be able to call the DeriveSha function on
a Transactions object, which would return the hash of the root of the trie consisted of
the Transaction objects
that are included in the Transactions object.
func (s TxByNonce) Less(i, j int) bool
Less
returns true if the i-th Transaction of a list of Transactions is less
than the j-th Transaction.
This is determined by only comparing the two
Transactions' nonces.
1.5 receipt.go
1.5.1 Data structures
type Receipt struct {
PostState []byte
CumulativeGasUsed *big.Int
Bloom []byte
logs state.Logs
}
The Receipt data structure represents
the receipts field of a Transaction.
The receipt contains certain information regarding the execution of the transaction
and are mainly used for providing logs and events regarding the transaction.
Each receipt is placed on a trie.
- PostState: the world state after the execution of the transaction
this receipt refers to.
- CumulativeGasUsed: The cumulative gas used up to and including the
current transaction of a Block.
- Bloom: A 'bloom' is composed from the log entries of the receipt.
This field is the 2048-bit hash of that bloom.
(See file bloom9.go)
- logs: A series of log entries. Each entry is a tuple of the logger’s address, a
possibly empty series of 32-byte log
topics, and some number of bytes of data.
The logs are created through the execution of a transaction.
type Receipts []*Receipt
The Receipts
data type is defined as a means to
- sort Receipt objects and
- derive the root hash of a trie consisting of a list of receipts.
1.5.2 Functions
func NewReceipt(root []byte, cumalativeGasUsed *big.Int) *Receipt
NewReceipt creates a new
Receipt provided the 'root' of
the receipts trie and the cumulative gas used, and returns it.
func NewRecieptFromValue(val *ethutil.Value) *Receipt
NewRecieptFromValue creates
a new Receipt from 'val' and returns it.
The val param should be the bytes representation of the rlp-encoded
Receipt object to be created.
func (self *Receipt) SetLogs(logs state.Logs)
SetLogs
sets the caller's logs field equal to the 'logs' parameter.
func (self *Receipt) RlpValueDecode(decoder *ethutil.Value)
RlpValueDecode
sets the caller's (Receipt)
fields to the rlp-decoded fields of the decoder parameter.
func (self *Receipt) RlpData() interface{}
RlpData
returns the rlp-encodable fields of the caller. The only difference between what
this function returns
and the caller's fields is that instead of the logs field
this function returns the result of the function call logs.RlpData().
func (self *Receipt) RlpEncode() []byte
RlpEncode
Returns the RLP-encoding of the rlp-encodable fields of a Receipt object.
These fields are obtained through the function
RlpData
func (self *Receipt) Cmp(other *Receipt) bool
Cmp
returns true if the caller Receipt is the same as the 'other', false otherwise.
Two Receipt objects are the same if their PostState fields are equal.
func (self *Receipt) String() string
String
returns the string representation of the caller.
func (self Receipts) RlpData() interface{}
RlpData returns the rlp-encodable
fields of the caller, aka an array that is populated with the result of the
consecutive calls to RlpData function
for each of the Receipt objects that the Receipts caller object consists of.
func (self Receipts) RlpEncode() []byte
RlpEncode returns the rlp-encoding
of the caller, aka rlp-encodes each Receipt object that the caller consists
of and returns the result.
func (self Receipts) Len() int
Len returns the number of Receipts that
the caller consists of.
This function, along with the GetRlp
function are implemented as parts of the
DerivableList
interface in order to be able to call the DeriveSha
function on a Receipts object, which would
return the hash of the root of the trie
consisted of the Receipt objects that are included in the
Receipts object.
func (self Receipts) GetRlp(i int) []byte
GetRlp returns the rlp-encoding of
the i-th Receipt of the caller.
This function, along with the
Len function are implemented as parts of the
DerivableList
interfacein order to be able to call the DeriveSha
function on a Receipts object, which would
return the hash of the root of the trie consisted of the Receipt objects
that are included in the
Receipts object.
1.6 bloom9.go
This file includes functions regarding the logsBloom field of a Block.
Every block contains many transactions. Each transaction has a receipt. Each receipt
has many logs. Each log consists of 3 fields: the address, the topics and the data.
The LogsBloom will be the lower 11 bits of the modulo operation by 2048 of the expression
kecchak-256(address and logs of all the receipts of the block's transactions).
"Events in the ethereum system must be easily searched for, so that applications can
filter and display events, including historical ones, without undue overhead. At the
same time, storage space is expensive, so we don't want to store a lot of duplicate data
- such as the list of transactions, and the logs they generate. The logs bloom filter
exists to resolve this.
When a block is generated or verified, the address of any logging contract,
and all the indexed fields from the logs generated by executing those transactions
are added to a bloom filter, which is included in the block header. The actual logs
are not included in the block data, to save space.
When an application wants to find all the log entries from a given contract, or with
specific indexed fields (or both), the node can quickly scan over the header of each
block, checking the bloom filter to see if it may contain relevant logs. If it does,
the node re-executes the transactions from that block, regenerating the logs, and
returning the relevant ones to the application."
Source:
https://ethereum.stackexchange.com/questions/3418/how-does-ethereum-make-use-of-bloom-filters
A thorough explanation on bloom filters:
https://brilliant.org/wiki/bloom-filter/
A complete example of the bloom filters on Ethereum:
https://medium.com/coinmonks/ethereum-under-the-hood-part-8-blocks-2-5fba93293213
1.6.1 Functions
func CreateBloom(receipts Receipts) []byte
CreateBloom creates the LogsBloom field
of the given 'receipts', aka the LogsBloom field of a
Block and returns it.
For each of the receipts, a logical OR operation happens between the so-far
result and the result of a call to the
LogsBloom
function call on the current
receipt. Finally, the overall result is left-padded by 64 bytes and returned.
func LogsBloom(logs state.Logs) *big.Int
LogsBloom returns the LogBloom of the param
logs, aka the LogBloom of a receipt, as a big.Int.
Steps to do so are as follows:
- Iterate over the logs field of the receipt.
- Create an array for every log. The array's first element will be the address of the log.
All other elements will be the topics of the log.
- Initialize the result to be returned to 0 and iterate over that array.
- result = (previous_result) | (lower 11 bits of kecchak-256(current_element_of_array) % 2048)
where the | operator is a logical OR operator.
func bloom9(b []byte) *big.Int
bloom9 is an inner function that
returns the lower 11 bits of b % 2048.
func BloomLookup(bin, topic []byte) bool
BloomLookup checks whether the bin bloom
has it's bit field of the 'topic' set to 1, aka the bloom may contain the 'topic'.
This function is only called by the
bloomFilter function defined in
the file core/filter.go. Even if the bit is set to 1 that
does not mean that the bin bloom will contain the topic. A bloom filter is like a
hash table where instead of storing the values
of the keys, a bit set to 1 indicates that there is a value with the specified key.
That means that multiple values with different
keys are mapped to the same bit field of the bloom filter.
Only if that bit field is 0 we know that the bloom does not
contain that value pair.
2. Package core
2.1 simple_pow.go
This file does not contain any code.
2.2 fees.go
Only contains the definition of the following variable:
var BlockReward *big.Int = big.NewInt(1.5e+18)
The BlockReward
represents the initial block reward for miners, set to 1.5 Ether.
Only the function
AccumelateRewards
defined in the file block_manager.go
uses this variable.
2.3 genesis.go
2.3.1 Data Structures
var ZeroHash256 = make([]byte, 32)
Used to set the parent's hash of the genesis block.
var ZeroHash160 = make([]byte, 20)
Used to set the coinbase of the genesis block.
var ZeroHash512 = make([]byte, 64)
Used to set the bloom field of the genesis block.
var EmptyShaList = crypto.Sha3(ethutil.Encode([]interface{}{}))
Used to set the root state of the genesis block.
var EmptyListRoot = crypto.Sha3(ethutil.Encode(""))
Used to set the tx root and receipt root of the genesis block.
var GenesisHeader = []interface{}{
ZeroHash256,
EmptyShaList,
ZeroHash160,
EmptyShaList,
EmptyListRoot,
EmptyListRoot,
ZeroHash512,
big.NewInt(131072),
ethutil.Big0,
big.NewInt(1000000),
ethutil.Big0,
ethutil.Big0,
nil,
crypto.Sha3(big.NewInt(42).Bytes()),
}
This is the special genesis block. The fields set are the same as those of a
Block.
- ZeroHash256: Previous hash (none)
- EmptyShaList: Empty uncles
- ZeroHash160: Coinbase, (aka miner's address)
- EmptyShaList: Root state
- EmptyListRoot: tx root
- EmptyListRoot: receipt root
- ZeroHash512: bloom field
- big.NewInt(131072): difficulty
- ethutil.Big0: block number
- big.NewInt(1000000): Block upper gas bound
- ethutil.Big0: Block gas used
- ethutil.Big0: Time field
- nil: Extra field.
- crypto.Sha3(big.NewInt(42).Bytes()): Nonce field
var Genesis = []interface{}{GenesisHeader, []interface{}{}, []interface{}{}}
Genesis
is defined so as to be able to RLP-encode the genesis block.
To rlp-encode any Block we provide it's header, transactions and uncles.
The genesis block does not have any transactions and uncles, thus the use
of the 2 empty objects.
This variable is only used by the function
NewChainManager defined in the file
chain_manager.go.
For example, the function
NewChainManager creates a new ChainManager object for which there
is a field that represents the genesis block. To set that block,
the NewChainManager function uses
the ethutil.Encode(Genesis) function.
2.4 block_manager.go
2.4.1 Data Structures
var statelogger = logger.NewLogger("BLOCK")
statelogger is a channel
used to log messages regarding Blocks processing.
type Peer interface {
Inbound() bool
LastSend() time.Time
LastPong() int64
Host() []byte
Port() uint16
Version() string
PingTime() string
Connected() *int32
Caps() *ethutil.Value
}
This interface is only implemented by a Peer object defined in the 'eth' package (file peer.go)
- Inbound(): Determines whether it's an inbound or outbound peer
- LastSend(): Last known message send time.
- LastPong(): Last received pong message
- Host(): the host.
- Port(): the port of the connection
- Version(): client identity
- PingTime(): Used to give some kind of pingtime to a node, not very accurate.
- Connected(): Flag for checking the peer's connectivity state
- Caps(): getter for the protocolCaps field of a Peer object.
type EthManager interface {
BlockManager() *BlockManager
ChainManager() *ChainManager
TxPool() *TxPool
Broadcast(msgType wire.MsgType, data []interface{})
PeerCount() int
IsMining() bool
IsListening() bool
Peers() *list.List
KeyManager() *crypto.KeyManager
ClientIdentity() wire.ClientIdentity
Db() ethutil.Database
EventMux() *event.TypeMux
}
The EthManager
interface is only implemented by the
'Ethereum' object, defined in the package 'eth' (file ethereum.go)
- BlockManager: Getter for the
BlockManager field of the Ethereum object
- ChainManager: Getter for the
ChainManager field of the Ethereum object
- TxPool: Getter for the
TxPool field of the Ethereum object.
- Broadcast: Used to broacast the 'data' msg to all peers.
- IsMining: Returns whether the peer is mining.
- IsListening: Returns whether the peer is listening.
- Peers: Returns all connected peers.
- KeyManager: Getter for the KeyManager field of the Ethereum object
- ClientIdentity: Getter for the ClientIdentity field of the Ethereum object.
That field is mainly used for communication between peers.
- Db: Getter for the ethereum database of the Ethereum object.
That field represents the World State.
- EventMux: Getter for the EventMux field of the Ethereum object.
That field is mainly used to dispatch events to registered nodes.
type BlockManager struct {
mutex sync.Mutex
bc *ChainManager
mem map[string]*big.Int
Pow pow.PoW
txpool *TxPool
lastAttemptedBlock *types.Block
events event.Subscription
eventMux *event.TypeMux
}
The BlockManager data
structure is essentially a state manager for processing new blocks
and managing the overall state.
- mutex: Mutex for locking the block processor as Blocks can
only be handled one at a time
- bc: Canonical block chain
- mem: non-persistent key/value memory storage
- Pow: Proof of work used for validating
- txpool: The transaction pool. See TxPool.
- lastAttemptedBlock: The last attempted block is mainly used for debugging purposes.
This does not have to be a valid block and will be set during 'Process' & canonical validation.
- events: Provides a way to subscribe to events.
- eventMux: event mutex, used to dispatch events to subscribers.
2.4.2 Functions
func NewBlockManager(txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockManager
NewBlockManager creates a new
BlockManager object by initializing these fields of a BlockManager object type:
mem, Pow, bc, eventMux, txpool. The Pow object will have it's turbo field
set to true when created.
See the type 'EasyPow' of the 'ezp' package for more (file pow/ezp/pow.go)
func (sm *BlockManager) TransitionState(statedb *state.StateDB, parent, block *types.Block) (receipts types.Receipts, err error)
TransitionState
returns (receipts, nil) or (nil, error) if an
GasLimitErr error has occured.
This function along with the
ApplyTransactions
function form a recursion algorithm meant to
apply all transactions of the current block to the world state. The main logic/
application happens
in the latter function. However, this function is the one
to be called when we want to apply the
transactions of a block. The
TransitionState
function sets the total gas pool (amount of gas left)
for the coinbase address of the block before calling the
ApplyTransactions
function which in turn
will call the TransitionState
function again, and so on, until all transactions have been applied or a
GasLimitErr error has occured.
If no such an error has occured then the 'receipts' object returned by
this function will hold the receipts that are
the result of the application of the transactions of the block param.
func (self *BlockManager) ApplyTransactions(
coinbase *state.StateObject,
state *state.StateDB,
block *types.Block,
txs types.Transactions,
transientProcess bool
)
(
types.Receipts,
types.Transactions,
types.Transactions,
types.Transactions,
error
)
The
ApplyTransactions
function will apply the transactions of a block to the world state and return
the results as a tuple.
It gets called by the
TransitionState
function, then calls the latter again, and so on, to form a recursion
algorithm that will apply the transactions one by one. In case where a
GasLimitErr
error occurs during the application of any transaction, the processing of the transactions stops.
Returns: (receipts, handled, unhandled, erroneous, err)
- receipts: The receipts up to but not including any transaction that has
caused a GasLimitErr error.
- handled: All transactions that were handled up to but not including
any transaction that has caused a
GasLimitErr error.
- unhandled: In case of a GasLimitErr
error this object will contain all the transactions that were not applied
(includes the transaction that caused the error). Otherwise, this object will be nil.
- erroneous: Any transactions that caused an error other than a
GasLimitErr
and/or a NonceErr errors.
- err: The err will be either a
GasLimitErr error or nil.
A short description on what this function does follows.
-
Clear all state logs.
-
Get (or create a new) coinbase state object and call the
TransitionState func.
-
The latter function will call this function again, forming the recursion.
-
If an error occured and is a
GasLimitErr
error then stop the process and set the unhandled variable
(to be returned later). If it is a NonceErr error,
ignore it. If it is any other error, also ignore it, but also append to the variable erroneous
(to be returned
later) the transaction that caused that error.
-
Calculate the gas used so far and the current reward for the miner.
Update the state.
-
Create the receipt of the current transaction and set the receipt's
logs and Bloom field.
-
If the parameter transientProcess is false, notify all subscribers
about the transaction.
-
Append receipt, transaction to the receipts, handled variables
(to be returned later)
-
When the processing has ended, set the block's reward and totalUsedGas fields.
-
Return the results.
func (sm *BlockManager) Process(block *types.Block) (td *big.Int, msgs state.Messages, err error)
Process
processes a block. When successful, returns the return result of a call to the
ProcessWithParent
function.
Otherwise, in case that the hash of the block or the hash of the parent of the
block already exist in the ChainManager,
returns the tuple (nil, nil KnownBlockError) or (nil, nil, ParentError) accordingly.
Before calling the
ProcessWithParent
function, Process
takes care of locking the BlockManager with a mutex and only after the
ProcessWithParent
function has returned the BlockManager
is unlocked.
func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.Int, messages state.Messages, err error)
ProcessWithParent
is the main process function of a block. Gets called by the function
Process.
Returns a tuple (td, messages, error) where
- td: total difficulty of the processed block_
- messages: messages generated by the application of the transactions of the block_
(and some extra messages like transactions regarding rewarding miners).
- If an error occured the returned tuple becomes (nil, nil, error).
If no errors have occured the returned tuple becomes (td, messages, nil).
Below follows a short description of what this function does:
- Saves a copy of the state. Also queues a reset of the state after the function's
return based on that copy. (use of golang's defer)
- Validates the block_ with a call to the function
ValidateBlock.
If errors happened, returns.
- Calls TransitionState to attempt to do the state transition.
If errors, returns.
- Creates the bloom field of the receipts returned from step 2.
If for some reason the bloom
field is different from the bloom field of the provided block_, it returns.
- Validates the transactions and the receipts root hashes.
If errors, returns.
- Calls AccumelateRewards
to calculate the miner rewards. If errors, returns.
- Sets the state to 0 and makes a call to CalculateTD in order to
calculate the total difficulty of the block_.
If errors, returns. If not, the last step is to remove the block_'s transactions from
the BlockManager's txpool,
sync the state db, cancel the queued state reset, send a message to
the chainlogger channel and finally
return the tuple (td, messages, nil).
func (sm *BlockManager) CalculateTD(block *types.Block) (*big.Int, bool)
BlockManager.CalculateTD
calculates the total difficulty for a given block. If the calculated total difficulty
is greater than the previous, the tuple (total_difficulty, true) is returned.
Otherwise, the tuple (nil, false) is returned.
TD(genesis_block)=0 and TD(block)=TD(block.parent) + sum(u.difficulty for u in block.uncles) + block.difficulty.
func (sm *BlockManager) ValidateBlock(block, parent *types.Block) error
BlockManager.ValidateBlock
validates the current block.
Returns an error if the block was invalid, an uncle or
anything that isn't on the current block chain.
Validation validates easy over difficult (dagger takes longer time = difficult)
func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent *types.Block) error
BlockManager.AccumelateRewards
calculates the reward of the miner.
Returns an error if an error has occured during the
validation process.
If no errors have occured, nil is returned. More specifically an error is returned if:
- the parent of any of the uncles of the block is nil, or
- the (block) number of the parent of any of the uncles of the block and
the block itself have a difference greater than 6, or
- the hash of any of the uncles of the param block matches any of the
uncles of the param parent.
- the nonce of any of the uncles of the param block is included in the nonce
of the block
The reward to be appointed to the miner will be:
Finally, a message is added to the state manifest regarding the value to
be transferred to the miner address.
This value will be the sum of the above
calculated reward and the block.Reward field.
func (sm *BlockManager) GetMessages(block *types.Block) (messages []*state.Message, err error)
BlockManager.GetMessages
returns either the tuple (state.Manifest().Messages, nil) or (nil, error).
If an error is returned it will be a
ParentError regarding the parent of the block
(the error includes the hash of the parent of the block). This error happens in the case where the the hash of the parent of the block already exists. In essence, the state manifest's messages
are the transactions that occured during the world state transition of the addition of a block. To get those messages a simple trick is used: a deferred call on state.Reset() is queued and only then a call of the function
TransitionState and following that a call on
AccumelateRewards is made.
2.5 chain_manager.go
2.5.1 Data Structures
var chainlogger = logger.NewLogger("CHAIN")
chainlogger is a channel
used to log messages regarding the chain.
type ChainManager struct {
processor types.BlockProcessor
eventMux *event.TypeMux
genesisBlock *types.Block
mu sync.RWMutex
td *big.Int
lastBlockNumber uint64
currentBlock *types.Block
lastBlockHash []byte
transState *state.StateDB
}
The ChainManager is mainly
used for the creation of the
Genesis or any other blocks.
- processor: An interface. A neat way of calling the
function Process of a BlockManager object.
- eventMux: Used to dispatch events to subscribers.
- genesisBlock: The special genesis block.
- mu: a mutex for the ChainManager object.
- td: the total difficulty.
TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty
- lastBlockNumber: the last block's number.
(the last successfully inserted block on the chain)
- currentBlock: During the creation of a new block, the
currentBlock will point to the parent
of the block to be created.
- lastBlockHash: the last block's hash.
- transState: represents the world state.
2.5.2 Functions
func AddTestNetFunds(block *types.Block)
AddTestNetFunds
sets the following accounts with a balance of
1606938044258990275541962092341162602522202 Ether for testing:
- 1ba59315b3a95761d0863b05ccc7a7f54703d99
- 4157b34ea9615cfbde6b4fda419828124b70c78
- 9c015918bdaba24b4ff057a92a3873d6eb201be
- c386a4b26f73c802f34673f7248bb118f97424a
- d2a3d9f938e13cd947ec05abc7fe734df8dd826
- ef47100e0787b915105fd5e3f4ff6752079d5cb
- 6716f9544a56c530d868e4bfbacb172315bdead
- a26338f0d905e295fccb71fa9ea849ffa12aaf4
This function gets only called indirectly from a
ChainManager object, and
more specifically from the functions
Reset and
setLastBlock.
The latter only calls this function if the chain has 0 blocks so far.
As one might have guessed already, when this functions gets called
the block parameter is always set to the
Genesis variable.
func CalcDifficulty(block, parent *types.Block) *big.Int
CalcDifficulty
calculates the difficulty of a block and returns it. If the block
was mined in less than 5 seconds, the difficulty of the block
is increased by 1/1024th of the parent's difficulty.
If the block was mined in more than 5 seconds, the difficulty is
decreased by 1/1024th
of the parent's difficulty.
func (self *ChainManager) Td() *big.Int
Td
returns the total difficulty.
TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty
func (self *ChainManager) LastBlockNumber() uint64
LastBlockNumber
returns the last block number.
func (self *ChainManager) LastBlockHash() []byte
LastBlockHash
returns the last block's hash.
func (self *ChainManager) CurrentBlock() *types.Block
CurrentBlock
returns the current block.
func NewChainManager(mux *event.TypeMux) *ChainManager
NewChainManager creates
and returns a new ChainManager object by setting the genesis block
and the eventMux field of the ChainManager. When creating the
Genesis block - or any other block -
the RLP-encoding of that block is used and this is the exact purpose of
the Genesis variable:
it represents the RLP-encodable fields of the genesis block.
func (self *ChainManager) SetProcessor(proc types.BlockProcessor)
SetProcessor
sets the processor field of the caller.
func (self *ChainManager) State() *state.StateDB
State
returns the world state.
Access on the current state happens through the
CurrentBlock field of the ChainManager object that
made the call to this function.
func (self *ChainManager) TransState() *state.StateDB
TransState
returns the transState field of the caller.
func (bc *ChainManager) setLastBlock()
setLastBlock
is an inner function, that gets called by the
NewChainManager function.
If the chain has 0 blocks so far,
setLastBlock
makes a call to the function
AddTestNetFunds
and also sets the currentBlock, lastBlockHash, lastBlockNumber
and td fields of the ChainManager.
Otherwise it makes a call to the
Reset function.
In all cases, a message is sent to the chainlogger
channel which logs the lastBlockNumber and currentBlock.Hash
fields of the ChainManager
after the processing has happened.
func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block
NewBlock
provides a way of creating a new block through a ChainManager
object. It creates a new
block by making a call to the function
CreateBlock,
sets the created block's difficulty, number and
gaslimit and returns the block. coinbase is the block's
beneficiary address. The ChainManager remains
locked starting with the call of this function
and until it has returned.
func (bc *ChainManager) Reset()
Reset
resets the chain to the point where the chain will only contain
the genesis block. This includes
the call of the function
AddTestNetFunds.
The
ChainManager remains locked starting with the call of
this function and until it has returned.
func (self *ChainManager) Export() []byte {
Export
returns the RLP-encoding of all blocks of the chain. A message is
sent to the chainlogger
channel containing the number of the currentBlock block field of
the ChainManager.
The ChainManager remains locked starting with the call of this
function and until it has returned.
func (bc *ChainManager) insert(block *types.Block)
insert is an
inner function, used to insert a block on the chain.
What actually gets inserted into the chain is the block's rlp-encoding.
This function is called by the
InsertChain and the
Reset functions.
func (bc *ChainManager) write(block *types.Block)
write is an
inner function, used to write a block to the database.
Gets called by the
InsertChain and the
Reset functions.
func (bc *ChainManager) Genesis() *types.Block
Genesis returns
the genesis block of the chain.
func (bc *ChainManager) HasBlock(hash []byte) bool
HasBlock returns
whether the given hash param matches the hash of a block of the chain.
func (self *ChainManager) GetChainHashesFromHash(hash []byte, max uint64) (chain [][]byte)
GetChainHashesFromHash
returns a list of hashes of the chain starting from the genesis
hash and up to, and including, the max block number.
The hash and the max params
should match the hash and the number of a specific block.
func (self *ChainManager) GetBlock(hash []byte) *types.Block
GetBlock
returns the block of the chain that has the given hash.
func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block
GetBlockByNumber
returns the block of the chain that has the given num.
func (bc *ChainManager) setTotalDifficulty(td *big.Int)
setTotalDifficulty
sets the total difficulty of the ChainManager object.
Also stores that information on the database.
func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error)
CalcTotalDiff
calculates the total difficulty of the ChainManager and returns
it in a tuple (td, nil).
If an error occured, then the tuple (nil, error) is returned.
TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty.
func (bc *ChainManager) BlockInfo(block *types.Block) types.BlockInfo
BlockInfo
returns the block's BlockInfo
object representation.
func (bc *ChainManager) writeBlockInfo(block *types.Block)
writeBlockInfo
is an inner function for writing the block's
BlockInfo
representation to the database.
This is extra information that normally should not be saved in
the db.
func (bc *ChainManager) Stop()
Stop
sends a stop message to the chain logger channel if and only if the currentBlock
field of the ChainManager caller object is not nil.
func (self *ChainManager) InsertChain(chain types.Blocks) error
InsertChain
iterates over the blocks in the chain param and does the following:
- It calls the
Process
method of the BlockProcessor
interface.
- writes the block to the database.
- sets the total difficulty of the block.
- inserts the block into the chain.
- posts a NewBlockEvent to the event mux.
- posts the messages to the event mux.
Returns: either nil for success or an error.
2.6 transaction_pool.go
2.6.1 Data Structures
var txplogger = logger.NewLogger("TXP")
txplogger is a channel
used to log messages regarding Blocks processing.
const txPoolQueueSize = 50
Used to initialize the queueChan field of a
TxPool
(which is used as a queue channel to reading and writing transactions)
type TxPoolHook chan *types.Transaction
Although defined, this type is never used in this go-ethereum version.
const (
minGasPrice = 1000000
)
Although defined, this variable is never used in this go-ethereum version.
var MinGasPrice = big.NewInt(10000000000000)
Although defined, this variable is never used in this go-ethereum version.
type TxMsgTy byte
The only use of a
TxMsgTy type is as a field of a
TxMsg type.
Although it's not clear how this type is supposed to be used,
since there are no other references to it in the whole codebase,
we could make a guess based on the fact that there are
3 types of transactions in ethereum:
- Regular transactions: a transaction from one wallet to another.
- Contract deployment transactions: a transaction without a to address,
where the data field is used for the contract code.
- Execution of a contract: a transaction that interacts with a
deployed smart contract.
In this case, to address is the smart contract address.
TxMsgTy may had been used to represent the above types
of transactions.
type TxMsg struct {
Tx *types.Transaction
Type TxMsgTy
}
TxMsg represents the type of the channel of
the subscribers field of a TxPool object.
However, that field is never actually used in the whole
codebase of this go-ethereum version.
type TxProcessor interface {
ProcessTransaction(tx *types.Transaction)
}
The
TxProcessor interface,
although defined, is not implemented at all in the whole codebase
of this go-ethereum version.
type TxPool struct {
mutex sync.Mutex
queueChan chan *types.Transaction
quit chan bool
pool *list.List
SecondaryProcessor TxProcessor
subscribers []chan TxMsg
broadcaster types.Broadcaster
chainManager *ChainManager
eventMux *event.TypeMux
}
TxPool is a thread safe transaction pool handler.
In order to guarantee a non blocking pool the queueChan
is used which can be independently read without needing access
to the actual pool. If the pool is being drained
or synced for whatever reason, the transactions
will simply queue up and be handled when the mutex is freed.
mutex: a mutex for accessing the Tx pool.
queueChan: Queueing channel for reading and writing incoming transactions to.
quit: Quiting channel (quitting is equivalent to emptying the TxPool)
pool: The actual pool, aka the list of transactions.
SecondaryProcessor: This field is actually never used as
the TxProcessor interface is not implemented.
subscribers: Although defined, this channel is never used.
broadcaster: used to broadcast messages to all connected peers.
chainManager: the chain to which the TxPool object is attached to.
eventMux: used to dispatch events to subscribers.
2.6.2 Functions
func EachTx(pool *list.List, it func(*types.Transaction, *list.Element) bool)
EachTx
is used as a means to iterate over the pool list of transactions.
func FindTx(pool *list.List, finder func(*types.Transaction, *list.Element) bool) *types.Transaction
FindTx
searches in the caller's transactions for finder and returns
either the matching transaction if found, or nil.
This is a neat way of searching for transactions that match the
criteria defined from the finder param. For example,
Add
uses the hash of a transaction as a searching criterion.
func NewTxPool(chainManager *ChainManager, broadcaster types.Broadcaster, eventMux *event.TypeMux) *TxPool
NewTxPool
creates a new
TxPool object and sets it's fields.
- TxPool.pool will be set to an empty list.
- TxPool.queueChain wil be set to a Transaction channel with a txPoolQueueSize size.
- TxPool.quit will be set to a boolean channel.
- TxPool.chainManager will be assigned the param chainManager.
- TxPool.eventMux will be assigned the param eventMux.
- TxPool.broadcaster will be assigned the param broadcaster.
All other fields of the
TxPool object that gets created are not set by NewTxPool.
func (pool *TxPool) addTransaction(tx *types.Transaction)
addTransaction
is an inner function used to add the
Transaction
tx to the end of the TxPool. This function also
broadcasts a msg to all peers which contains
the rlp-encodable fields of the tx
(See RlpData).
The TxPool
remains locked starting with the call of this function
and until it has returned.
func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error
ValidateTransaction
validates the tx
Transaction.
Returns either an error if tx can not be validated or nil.
These are the cases where tx is not validated:
- For some reason, the currentBlock field of the chainManager field
of the caller is nil. (aka the chain is empty)
- The recipient field (to) of tx is is either nil or != 20 bytes.
This means that trying to validate contract creation
transactions, (for which the recipient to is set to nil)
will always return an error.
- The v field of tx is neither 28 nor 27. (See
Transaction)
- The sender account of tx does not have enough Ether to send to the recipient of tx.
func (self *TxPool) Add(tx *types.Transaction) error
Add
is the function to be called for adding a
Transaction to the
TxPool caller.
Returns either an error on not successfully
adding tx or nil for success. If tx was added,
a message is posted to the subscribed peers,
containing the tx from, to, value
and hash fields. An error is returned in any of these cases:
- tx's hash already exists in the
TxPool caller, aka the transaction
to be added is already part of the caller.
- tx validation returned an error when calling
ValidateTransaction.
If no errors are produced from steps 1 and 2,
Add makes a call to the inner
function
addTransaction to add tx to the current
TxPool.
func (self *TxPool) Size() int
Size
returns the number of Transactions of the caller.
func (pool *TxPool) CurrentTransactions() []*types.Transaction
CurrentTransactions
returns the transactions of the
TxPool caller as a slice.
func (pool *TxPool) RemoveInvalid(state *state.StateDB)
RemoveInvalid
removed all transactions from the caller for which either:
- the transaction returns an error when validated through the
ValidateTransaction function, or
- the transaction sender's nonce field is >= to the transaction's nonce field.
func (self *TxPool) RemoveSet(txs types.Transactions)
RemoveSet
takes as an argument a set of transactions txs and
removes from the caller's transactions set those that
match the ones from txs. Looping over the transactions
of the caller happens through the
EachTx function.
func (pool *TxPool) Flush() []*types.Transaction
Flush
resets the caller's transactions list to an empty list.
func (pool *TxPool) Start()
Although defined, this function does not contain any executable code in this go-ethereum version.
func (pool *TxPool) Stop()
Stop
makes a call on
Flush
to empty the caller's transactions list
and then sends the message "Stopped" to the
txplogger channel.
2.7 asm.go
The file contains only one function:
func Disassemble(script []byte) (asm []string)
Disassemble returns a
string representation of a sequence of bytes that consist an evm bytecode.
The opcodes are defined in vm/types.go.
In case that we have a PUSHi opcode we expect the next i
bytes to be the i items that we want to push to the stack.
script: The evm bytecode.
An example can be found here:
https://rinkeby.etherscan.io/address/0x147b8eb97fd247d06c4006d269c90c1908fb5d54#code
Example: Passing the first series of bytes of the above link to this function as
script := []byte(
0x60, 0x80, 0x60, 0x40, 0x52, 0x34,
0x80, 0x15, 0x61, 0x00, 0x10, 0x57,
0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50
)
will yield the following output which is presented in a more human-readable way.
The first column is only there to show match the bytes of the input with the results.
0x60 --> 0000: PUSH1
0x80 --> 0001: 0x80
0x60 --> 0002: PUSH1 (next value is pushed onto the stack)
0x40 --> 0003: 0x40
0x52 --> 0004: MSTORE
0x34 --> 0005: CALLVALUE
0x80 --> 0006: DUP1
0x15 --> 0007: ISZERO
0x61 --> 0008: PUSH2 (next 2 values are pushed onto the stack)
0x00 --> 0009: 0x00
0x10 --> 0010: 0x10
0x57 --> 0011: JUMPI
0x60 --> 0012: PUSH1
0x00 --> 0013: 0x00
0x80 --> 0014: DUP1
0xfd --> 0015: Missing opcode 0xfd
0x5b --> 0016: JUMPDEST
0x50 --> 0017: POP
2.8 error.go
2.8.1 Data structures
type UncleErr struct {
Message string
}
UncleErr error.
This error is thrown only from the function
AccumelateRewards.
type ParentErr struct {
Message string
}
ParentErr error.
In case a parent is unknown this error will be thrown by the block manager.
type ValidationErr struct {
Message string
}
ValidationErr
is a block validation error.
If any validation fails, this error will be thrown.
type GasLimitErr struct {
Message string
Is, Max *big.Int
}
A GasLimitErr
happens when the total gas left for the coinbase address
is less than the gas to be bought.
type NonceErr struct {
Message string
Is, Exp uint64
}
A NonceErr
happens when a transaction's nonce is incorrect.
type OutOfGasErr struct {
Message string
}
A OutOfGasErr
happens when the gas provided runs out before the state transition happens.
type TDError struct {
a, b *big.Int
}
TDError is defined, but
never used in this go-ethereum version.
Meant to be used as a total difficulty error.
type KnownBlockError struct {
number *big.Int
hash []byte
}
A KnownBlockError
happens when there is already a block in the chain with the same hash.
The number field is the number of the existing block.
2.8.2 Functions
func (self *TDError) Error() string
TDError.Error
creates and returns a TDError error.
func (self *KnownBlockError) Error() string
KnownBlockError.Error
creates and returns a KnownBlockError error.
func ParentError(hash []byte) error
ParentError
creates a ParentError object by setting it's message to a message
that includes the 'hash' and returns it.
func UncleError(str string) error
UncleError
creates an UncleErr error by setting it's message to 'str' and returns it.
func ValidationError(format string, v ...interface{}) *ValidationErr
ValidationError
creates a ValidationErr error by setting it's message and returns it.
func GasLimitError(is, max *big.Int) *GasLimitErr
GasLimitError
creates and returns a GasLimitError given the total gas left
to be bought by a coinbase address and the actual gas.
func NonceError(is, exp uint64) *NonceErr
NonceError
creates and returns a NonceError given the transaction's nonce
and the nonce of the sender of the transaction.
func OutOfGasError() *OutOfGasErr
OutOfGasError
creates and returns an OutOfGasError error.
func IsParentErr(err error) bool
IsParentErr
returns whether 'err' is a ParentErr error.
func IsUncleErr(err error) bool
IsUncleErr
returns whether 'err' is an UncleErr error.
func IsValidationErr(err error) bool
IsValidationErr
returns whether 'err' is a ValidationErr error.
func IsGasLimitErr(err error) bool
IsGasLimitErr
returns whether 'err' is a GasLimitErr error.
func IsNonceErr(err error) bool
IsNonceErr
returns whether 'err' is a NonceErr error.
func IsOutOfGasErr(err error) bool
IsOutOfGasErr
returns whether 'err' is an OutOfGasErr error.
func IsTDError(e error) bool
IsTDError
returns whether 'e' is a TDError error.
func IsKnownBlockErr(e error) bool
IsKnownBlockErr
returns whether 'e' is a KnownBlockErr error.
func (err *ParentErr) Error() string
ParentErr.Error
returns the error message of the caller.
func (err *UncleErr) Error() string
UncleErr.Error
returns the error message of an UncleErr error.
func (err *ValidationErr) Error() string
ValidationErr.Error
returns the error message of a ValidationErr error.
func (err *GasLimitErr) Error() string
GasLimitErr.Error
returns the error message of a GasLimitErr error.
func (err *NonceErr) Error() string
returns the error message of a NonceErr error.
func (self *OutOfGasErr) Error() string
OutOfGasErr.Error
returns the error message of an OutOfGasError error.
2.9 event.go
2.9.1 Data Structures
type TxPreEvent struct{ Tx *types.Transaction }
A TxPreEvent
is posted when a transaction enters the transaction pool.
type TxPostEvent struct{ Tx *types.Transaction }
A TxPostEvent
is posted when a transaction has been processed.
type NewBlockEvent struct{ Block *types.Block }
A NewBlockEvent
is posted when a block has been imported.
2.10 dagger.go
Dagger is the consensus algorithm.
Dagger was proven to be vulnerable to shared memory hardware acceleration:
https://bitslog.com/2014/01/17/ethereum-dagger-pow-is-flawed/
The consensus algorithm for Ethereum 1.0 is Ethash (PoW algorithm):
https://eth.wiki/en/concepts/ethash/ethash
Essentially, the Dagger
algorithm works by creating a directed acyclic graph with ten levels
including the root and a total of 225 - 1 values. In levels 1 through 8, the value of each node
depends on three nodes in the level above it, and the number of nodes in each level is eight
times larger than in the previous. In level 9, the value of each node depends on 16 of its
parents, and the level is only twice as large as the previous; the purpose of this is to make the
natural time-memory tradeoff attack be artificially costly to implement at the first level, so that
it would not be a viable strategy to implement any time-memory tradeoff optimizations at all.
Finally, the algorithm uses the underlying data, combined with a nonce, to pseudorandomly select
eight bottom-level nodes in the graph, and computes the hash of all of these nodes put together.
If the miner finds a nonce such that this resulting hash is below 2^256 divided by the difficulty
parameter, the result is a valid proof of work.
Here is the breakdown of the algorithm that the below functions implement:
- D: block header
- N: nonce
- ||: string concatenation operator.
if L==9
dependsOn(L)=16
else
dependsOn(L)=3
Node(D,xn,0,0)=D
Node(D,xn,L,i) =
for k in [0...dependsOn(L)-1]
p[k] = sha256(D || xn || L || i || k) mod 8^(L-1)
sha256(node(L-1,p[0]) || node(L-1,p[1]) ... || node(L-1,p[dependsOn(L)-1]))
eval(D,N) =
for k in [0...3]
p[k] = sha256( D || floor(n / 2^26) || i || k ) mod 8^8 * 2
sha256( node( D,floor(n / 2^26),9,p[0]) || node(D,floor(n / 2^26),9,p[1]) ...
... || node(D,floor(n / 2^26),9,p[3])))
Objective: find k such that eval(D,k) < 2^256 / diff
2.10.1 Functions
func (dag *Dagger) Find(obj *big.Int, resChan chan int64)
func (dag *Dagger) Search(hash, diff *big.Int) *big.Int
func (dag *Dagger) Verify(hash, diff, nonce *big.Int) bool
func DaggerVerify(hash, diff, nonce *big.Int) bool
func (dag *Dagger) Node(L uint64, i uint64) *big.Int
func Sum(sha hash.Hash) []byte
func (dag *Dagger) Eval(N *big.Int) *big.Int
2.11 state_transition.go
2.11.1 Data Structures
type StateTransition struct {
coinbase, receiver []byte
msg Message
gas, gasPrice *big.Int
initialGas *big.Int
value *big.Int
data []byte
state *state.StateDB
block *types.Block
cb, rec, sen *state.StateObject
Env vm.Environment
}
A StateTransition.
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:
- Nonce handling
- Pre pay / buy gas of the coinbase (miner)
- Create a new state object if the recipient is 0, aka contract creation.
- Value transfer
== If contract creation ==
4a. Attempt to run transaction data
4b. If valid, use result as code for the new state object
== end ==
- Run Script section
- Derive the new state root
- coinbase: The miner state object.
- receiver: The receiver state object (in case of Ether transfer)
- msg: Representation of the transaction to be applied.
- gas: The gas limit equal to the maximum amount of gas that should be
used when executing the msg/transaction.
- gasPrice: This is equal to the number of Wei to be paid per unit of gas for
all computation costs incurred as a result of the execution of the msg/transaction.
- initialGas: The gas that has been supplied for the execution of the msg/transaction.
- value: The amount of Wei to be transferred.
- data: An unlimited size byte array specifying the input data of the
msg/transaction.
The first 4 bytes of this field specify which function to call
when the msg/transaction
will execute by using the hash of the function's name
to be called and it's arguments.
The rest of the data field are the arguments
passed to the function.
If the data field is empty, it means a msg/transaction is for a payment and not
an execution of the contract.
- state: The current world state before the execution of the msg/transaction.
- block: The block (to be added to the chain) that contains the msg to be executed.
- cb: The miner's address.
- rec: The receiver's address.
- sen: The sender's address.
type Message interface {
Hash() []byte
From() []byte
To() []byte
GasPrice() *big.Int
Gas() *big.Int
Value() *big.Int
Nonce() uint64
Data() []byte
}
A Message
represents a transaction. All functions of this interface are
getter functions for the relevant fields of the msg/transaction.
2.11.2 Functions
func AddressFromMessage(msg Message) []byte
AddressFromMessage
creates and returns a new address based on the msg sender and nonce fields.
func MessageCreatesContract(msg Message) bool
MessageCreatesContract
returns whether the msg is a contract creation aka whether the msg
recipient is 0.
func MessageGasValue(msg Message) *big.Int
MessageGasValue
returns the amount of Wei based on the msg gas and gasPrice fields.
gasValue = gas * gasPrice
func NewStateTransition(coinbase *state.StateObject, msg Message, state *state.StateDB, block *types.Block) *StateTransition
NewStateTransition
creates and returns a StateTransition object.
The fields gas and initialGas are set to 0.
The fields rec, sen and Env are set to nil.
The field coinbase is set to the address of the coinbase param.
The field cb is set to the param coinbase.
All other fields are set to the corresponding params.
func (self *StateTransition) VmEnv() vm.Environment
VmEnv
is a getter method for the Env field of a
StateTransition object.
If the Env field of the caller is nil, a new Env is created by
calling the function NewEnv.
func (self *StateTransition) Coinbase() *state.StateObject
Coinbase
returns the miner of the msg's block. If the miner does
not exist in the current world state, it's created.
func (self *StateTransition) From() *state.StateObject
From
returns the from field of the msg. If
from does not exist in the current world state, it's created.
func (self *StateTransition) To() *state.StateObject
To
returns the to field of the msg. If
to does not exist in the current world state, it's created.
This function will return nil in the case where the msg is about
a contract creation (aka if to is 0)
func (self *StateTransition) UseGas(amount *big.Int) error
UseGas
attempts to use amount gas of the caller's gas. If the caller's
gas is less than the amount provided,
an OutOfGasError is returned.
Otherwise, nil is returned for success. In case of success, the new
gas of the caller will become:
newGas = prevGas - amount.
func (self *StateTransition) AddGas(amount *big.Int)
AddGas
adds amount gas to the caller's gas. Helps in keeping track of the
altogether used gas of a list of transactions.
func (self *StateTransition) BuyGas() error
BuyGas
attempts to reward the miner with the gas of the transaction.
If the sender's balance is less than the calculated gas in Wei
(gas*gasPrice of caller), an error is returned.
Buying the gas does not directly happen in this function. Instead,
the BuyGas function of the miner (StateObject) is called through
this function. If the latter does not return an error, this function
will increase the gas field of the caller, set the caller's
initialGas field and decrease the sender's balance by an amount
of gas *gasPrice
func (self *StateTransition) preCheck() (err error)
preCheck
is an inner function, used by the
TransitionState
function and does 2 things:
- Checks whether the caller's msg sender nonce is the same as the caller's msg nonce.
If not, it returns an error.
- Calls
BuyGas in order to reward the miner.
If BuyGas returns an error,
this function returns that error.
If everything went well, this function returns nil.
func (self *StateTransition) TransitionState() (ret []byte, err error)
TransitionState
attempts to alter the world state by applying the msg/transaction of the caller.
- Calls preCheck
for nonce validation and to reward the miner.
- Schedules a gas refund (to return the unused gas)
- increases nonce of the msg sender.
- uses the TxGas. (defined as Gtransaction in the Ethereum Yellow Paper)
TxGas is a constant value set to 500 Wei. (see the GasTx variable defined in vm/common.go)
On the Ethereum Yellow Paper this value is set to 21000 Wei.
- uses the GasData. This is the gas that must be payed for every byte
of the log field of the msg. On the Ethereum Yellow Paper this value is set to 8 Wei per byte.
- If the msg is about a contract creation (msg recipient is 0) this function makes a call
to the MakeContract, uses the appropriate gas needed and sets the code of the to-be-deployed contract.
- If the msg is not a contract creation msg, a call to the vm's
Call function is made. The vm takes care of executing the transaction and may return an error.
- In case where none of the above operations returned an error, a call on
UseGas is made.
- As usual, in case of any errors the returned tuple will be (nil, error) or in case
of no errors, the error returned will be nil and the ret field of the tuple will
contain the returned result of the vm of steps 6 or 7.
func MakeContract(msg Message, state *state.StateDB) *state.StateObject
MakeContract
converts an transaction in to a state object. The stateObject that this function
creates and returns may then be used (as a param) to actually deploy the contract through the
vm Create function.
func (self *StateTransition) RefundGas()
RefundGas
takes care of refunding gas any remaining gas in case of a successful msg/transaction execution.
func (self *StateTransition) GasUsed() *big.Int
GasUsed
returns how much gas has been used by the execution of the msg/transaction
2.12 vm_env.go
2.12.1 Data Structures
type VMEnv struct {
state *state.StateDB
block *types.Block
msg Message
depth int
}
The VMEnv represents the Ethereum Virtual Machine.
- state: The current world state.
- block: The block to which the msg/transaction to be executed belongs to.
- msg: The msg/transaction to be executed.
- depth: The EVM operates as a stack machine. This variable is the maximum number
of items the stack can hold.
2.12.2 Functions
func NewEnv(state *state.StateDB, msg Message, block *types.Block) *VMEnv
creates and returns a new VMEnv object.
The VMEnv implements the Environment interface.
For that reason, the following functions are implemented:
func (self *VMEnv) Origin() []byte { return self.msg.From() }
Origin
is defined as part of the implementation of the Environment interface for a VMEnv object,
which returns the origin of the msg to be executed.
func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number }
BlockNumber
is defined as part of the implementation of the Environment interface for a VMEnv object,
which returns the block number of the block to which the msg to executed belongs to.
func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash }
PrevHash
is defined as part of the implementation of the Environment interface for a VMEnv object,
which returns the hash of the parent of the block that contains the msg to be executed.
func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase }
Coinbase
is defined as part of the implementation of the Environment interface for a VMEnv object,
which returns the miner's address of the block that contains the msg to be executed.
func (self *VMEnv) Time() int64 { return self.block.Time }
Time
is defined as part of the implementation of the Environment interface for a VMEnv object,
which returns the time that the block that contains the msg to be executed will be/is created.
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty }
Difficulty
is defined as part of the implementation of the Environment interface for a VMEnv object,
which returns the difficulty of the block that contains the msg to be executed.
func (self *VMEnv) BlockHash() []byte { return self.block.Hash() }
BlockHash
is defined as part of the implementation of the Environment interface for a VMEnv object,
which returns the hash of the block that contains the msg to be executed.
func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
Value
is defined as part of the implementation of the Environment interface for a VMEnv object,
which returns the value in Wei of the msg to be executed.
func (self *VMEnv) State() *state.StateDB { return self.state }
State
is defined as part of the implementation of the Environment interface for a VMEnv object,
which returns the current world state.
func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit }
GasLimit
is defined as part of the implementation of the Environment interface for a VMEnv object,
which returns the gasLimit field of the block that contains the msg to be executed.
func (self *VMEnv) Depth() int { return self.depth }
Depth
is defined as part of the implementation of the Environment interface for a VMEnv object,
which returns the maximum number of items of the EVM stack.
func (self *VMEnv) SetDepth(i int) { self.depth = i }
SetDepth
is defined as part of the implementation of the Environment interface for a VMEnv object,
which sets the maximum number of items of the EVM stack.
func (self *VMEnv) AddLog(log state.Log) { self.state.AddLog(log) }
AddLog
is defined as part of the implementation of the Environment interface for a VMEnv object,
which adds a log to the world state through the function AddLog of a StateDB object
(defined in the file state/state.go).
func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error
Transfer makes use of the generic function
Transfer defined in the file vm/environment.go to
make the transfer of amount Wei from the from to the to accounts.
Returns nil on success or an error if there is not sufficient balance in the from
account.
func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *Execution
vm
is an inner function that creates and returns a new
Execution object.
func (self *VMEnv) Call(me vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error)
Call
is defined as part of the implementation of the Environment interface for a VMEnv object,
which executes the contract associated at addr with the given data.
This happens through a call on the inner function
exec.
func (self *VMEnv) CallCode(me vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error)
CallCode
is defined as part of the implementation of the Environment interface for a VMEnv object,
which executes the contract associated at addr with the given data.
This happens through a call on the inner function
exec. The only
diffference between Call and CallCode
is that the latter executes the given address'
code with the caller as context (aka CallCode is used when a function calls
another function with the 1st function being the caller).
func (self *VMEnv) Create(me vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ClosureRef)
Create
is defined as part of the implementation of the Environment interface for a VMEnv object,
which creates a contract through the function
Create</a.
2.13 execution.go
2.13.1 Data Structures
type Execution struct {
env vm.Environment
address, input []byte
Gas, price, value *big.Int
SkipTransfer bool
}
The EVM always creates an
Execution object
and then calls upon it's functions in order to execute any transaction.
In other words, this is the core object through which any code on the blockchain is executed.
- env: The Execution object needs to be "attached" to an EVM.
- address: The address of the Execution. This should be a contract's address as it
refers to an address which contains the code to be executed.
- input: The code to be executed. This param should be of the form
{hash, params}, where hash is the hash of the function's signature to be executed
and params are 32-byte words which are passed as params to the function. This is where
the stack comes into play.
- Gas: The gas that has been supplied for the the msg/transaction.
- price: The gas price.
- value: Amount of Wei to be transferred throught the execution of the transaction.
- SkipTransfer: Used only for testing.
2.13.2 Functions
func NewExecution(env vm.Environment, address, input []byte, gas, gasPrice, value *big.Int) *Execution
NewExecution is a contructor for an
Execution object. This function gets
mainly called from the EVM to create an Execution object through which (the EVM)
will call either Call or
Create in order to execute code or
create a contract accordingly.
func (self *Execution) Addr() []byte
Addr
returns the address of the Execution.
func (self *Execution) Call(codeAddr []byte, caller vm.ClosureRef) ([]byte, error)
Call
is the function to be called when a msg/transaction is not about contract creation.
It does nothing more than retrieving the code of the codeAddr (to be executed)
and makes a call to the inner function exec which takes care of the execution.
This function gets called from both
CallCode and
Call functions of the EVM.
func (self *Execution) exec(code, contextAddr []byte, caller vm.ClosureRef) (ret []byte, err error)
exec
is the most important function of the whole core package and one of the most important
ones of the whole go-ethereum codebase. First of all, it's an inner function, called by
Call and/or
Create.
exec executes the code from the contract codeAddr.
It handles any necessary value transfer required and takes
the necessary steps to create accounts and reverses the state in case of an
execution error or failed value transfer.
- caller: In cases where eg. a function A
calls function B, the caller param will point to the the contract's address
that made the call to B.
- contextAddr: The address of the contract that includes the code to be
executed.
func (self *Execution) Create(caller vm.ClosureRef) (ret []byte, err error, account *state.StateObject)
Create
creates a new contract and returns it's bytecode and the account created as a StateObject.