Objective
This period of time has been doing blockchain public chain project development, mainly based on Bitcoin-core source code development, understanding the principle of blockchain and basic concepts; The individual is also interested in Ethereum, so prepare to take go-ethereum to learn, the process will last a few months, here to record the study notes I now to Ethereum is also rookie small white, this article is mainly aimed at go-ethereum small white, Daniel please bypass it.
Let's start now.
The basic concept of blockchain: trading, block, blockchain , is the core of the blockchain, today from the concept of the analysis of it. (here can not help to say a few words, any scientific field of basic concepts is really important, many problems encountered in the work is because the basic concepts are not in place, to solve the problem needs to re-understand the basic concepts; still remember a few years ago Nanjing University Professor Xu Jiafu speech, a classmate asked how to learn computer, Professor Xu did not say anything, picked up the chalk on the blackboard trembling handwriting to: "Basic concepts, basic concepts, basic concepts", you know the importance of basic knowledge of it. If you do not know Professor Xu go to Baidu, the New China computer field of one of the founders, academia popular a word "north of Fuqing Yang (Tsinghua), south of Xu Jiafu (south)").
Transaction
Core/types/transaction.go
Type Transaction struct {
Data txdata//transaction content, stored in TxData type
Caches the following three fields are stored in memory only?
Hash atomic. Value//hash of the transaction
Size atomic. Value//size of trade
From Atomic. Value//Initiator of the transaction
}
Type TxData struct {
Accountnonce UInt64//account nonce? Why, I don't know.
Price *big. INT//Gasprice
Gaslimit UInt64//Gaslimit, we know that setting gas limit when writing smart contracts can prevent programs from consuming too much gas
Recipient *common. Address//Transaction receiver, nil means contract creation
Amount *big. INT//Trade The number of ether?? Pending confirmation
Payload []byte//trading can carry Payload, the byte code of the smart contract is stored here?? Pending confirmation
Signature values, related to the signature, not to delve into
V *big. Int
R *big. Int
S *big. Int
This is a used when the marshaling to JSON.
Hash *common. Hash
}
The above is the definition of the structure of the transaction, and the following is a look at the functions and methods associated with the transaction (Golang concepts of both functions and methods).
Func newtransaction (Nonce UInt64, to common. Address, amount *big. Int, Gaslimit UInt64, Gasprice *big. INT, data []byte]
*transaction {
Return Newtransaction (nonce, &to, amount, Gaslimit, Gasprice, data)
}
Func newcontractcreation (nonce UInt64, amount *big. Int, Gaslimit UInt64, Gasprice *big. INT, data []byte] *transaction {
Return newtransaction (nonce, nil, amount, gaslimit, Gasprice, data)
}
The above function, Newtransaction is to create a normal trade, newcontractcreation is used to create a smart contract, both call the intrinsic function (non-export) newtransaction, The difference is obviously that Newcontractcreation set the transaction receive address to nil.
Func newtransaction (Nonce UInt64, to *common. Address, amount *big. Int, Gaslimit UInt64, Gasprice *big. INT, data []byte]
*transaction {
If Len (data) > 0 {
data = Common. Copybytes (data)
}
D: = txdata{
Accountnonce:nonce,
Recipient:to,
Payload:data,
Amount:new (big. INT),
Gaslimit:gaslimit,
Price:new (big. INT),
V:new (big. INT),
R:new (big. INT),
S:new (big. INT),
}
If amount! = Nil {
D.amount.set (Amount)
}
If Gasprice! = Nil {
D.price.set (Gasprice)
}
Return &TRANSACTION{DATA:D}
}
The above functions are simple, create a TxData object first, and then initialize the data member.
The following ENCODERLP and DECODERLP are primarily responsible for the RLP codec of the transaction.
ENCODERLP implements RLP. Encoder
Func (TX *transaction) ENCODERLP (w io). Writer) Error {
Return RLP. Encode (W, &tx.data)
}
DECODERLP implements RLP. Decoder
Func (TX *transaction) DECODERLP (S *RLP. Stream) Error {
_, size, _: = S.kind ()
ERR: = S.decode (&tx.data)
If Err = = Nil {
Tx.size.Store (Common. Storagesize (RLP. Listsize (size)))
}
return err
}
Here is a brief introduction to several trading-related functions and methods, more functions and methods you can consult the source code. The reason why I do not expand is to pursue the whole understanding first, then the concrete realization.
Block
Core/types/block.go
First look at the data structure of the chunk header:
Header represents a block header in the Ethereum blockchain.
Type Header struct {
Parenthash Common. Hash/hash of the previous block, used to organize the block into a chain
Unclehash Common. Hash//unclehash, understanding is not too deep, and later
Coinbase Common. Address//pow consensus algorithm Coinbase transaction correspondence
Root Common. Hash//State trie tree Root
Txhash Common. Hash//Transactions Root
Receipthash Common. Hash//Receipts Root
Bloom Bloom//should be Bloom filter, not in depth
Difficulty *big. The difficulty value of the Int//pow consensus algorithm is adjusted with the block chain height
Number *big. Int//Block height
Gaslimit UInt64//block head of the Gaslimit?? It's not clear what the effect is.
gasused UInt64//The entire chunk of the consumed gas traded? Pending confirmation
Time *big. Int//Out block time
Extra []byte
Mixdigest Common. Hash//Temporarily do not know what to do
Nonce in nonce blocknonce//pow consensus algorithm
}
The following method gets the hash value of the block header:
Hash returns the block hash of the header, which is simply the keccak256 hash of its
RLP encoding.
Func (H *header) Hash () common. Hash {
return Rlphash (h)
}
Hashnononce returns the hash which is used as input for the proof-of-work search.
Func (H *header) hashnononce () common. Hash {
Return Rlphash ([]interface{}{
H.parenthash,
H.unclehash,
H.coinbase,
H.root,
H.txhash,
H.receipthash,
H.bloom,
H.difficulty,
H.number,
H.gaslimit,
H.gasused,
H.time,
H.extra,
})
}
Func rlphash (x interface{}) (H common. Hash) {
HW: = Sha3. NEWKECCAK256 ()
Rlp. Encode (HW, X)
Hw. Sum (h[:0])
Return h
}
The following is the data structure of the block body:
Body is a simple (mutable, non-safe) data container for storing and moving
A block ' s data contents (transactions and uncles) together.
Type Body struct {
transactions [All trades in]*transaction//block body
Uncles []*header//not quite understand the role of this field, is it related to the fork?
}
The data structure of the block is as follows:
Block represents an entire block in the Ethereum blockchain.
Type Block struct {
Header *header//block head pointer
Uncles []*header
Transactions transactions//chunks in the body of the transaction
Caches
Hash atomic. Value
Size atomic. Value
Td is used by package core to store the total difficulty
Of the chain up to and including the block.
TD *big. INT//The overall difficulty value on the chain
These fields is used by package ETH-to-track
Inter-peer block relay.
As comments, these two fields are used to track the forwarding of chunks between nodes
Receivedat time. Time//Chunk received
Receivedfrom interface{}//Flag This chunk is received from which peer node
}
Storageblock defines the RLP encoding of a Block stored in the
State database. The Storageblock encoding contains fields
Would otherwise need to be recomputed.
Type Storageblock Block
"External" block encoding. Used for ETH protocol, etc.
Type Extblock struct {
Header *header
Txs []*transaction
Uncles []*header
}
The block data structure above is stored in memory, the actual structure stored in the database is Storageblock, defined as follows:
"Storage" block encoding. Used for database.
Type Storageblock struct {
Header *header
Txs []*transaction
Uncles []*header
TD *big. Int
}
Below is a simple analysis of the function Newblock to create a block:
Newblock creates a new block. The input data is copied,
Changes to header and to the field values would not affect the block.
The values of Txhash, Unclehash, Receipthash and Bloom in header
is ignored and set to values derived from the given txs, uncles and receipts.
Func Newblock (header *header, TXs []*transaction, uncles []*header, receipts []*receipt] *block {
B: = &block{header:copyheader (header), Td:new (big. INT)}//Create block Object
Todo:panic If Len (txs)! = Len (receipts)
If Len (txs) = = 0 {
B.header.txhash = emptyroothash//If there is no transaction in the block, the Txhash assignment is Emptyroothash
} else {
B.header.txhash = Derivesha (Transactions (TXS))
B.transactions = Make (Transactions, Len (TXS))
Copy (b.transactions, TXS)//Create and copy a copy of TX
}
If len (receipts) = = 0 {
B.header.receipthash = Emptyroothash
} else {
B.header.receipthash = Derivesha (receipts (receipts))
B.header.bloom = createbloom (receipts)
}
If Len (uncles) = = 0 {
B.header.unclehash = Emptyunclehash
} else {
B.header.unclehash = Calcunclehash (uncles)
B.uncles = Make ([]*header, Len (uncles))
For I: = Range Uncles {
B.uncles[i] = Copyheader (Uncles[i])
}
}
Return b
}
Newblockwithheader creates a block with the given header data. The
Header data is copied, changes to header and to the field values
Would not affect the block.
Func Newblockwithheader (header *header) *block {
Return &block{header:copyheader (header)}
}
The DECODERLP and ENCODERLP methods are the concrete implementations of Block's RLP codec:
DECODERLP decodes the Ethereum
Func (b *block) DECODERLP (S *RLP. Stream) Error {
var eb extblock
_, size, _: = S.kind ()
If err: = S.decode (&EB); Err! = Nil {
return err
}
B.header, b.uncles, b.transactions = EB. Header, EB. Uncles, EB. Txs
B.size.store (Common. Storagesize (RLP. Listsize (size)))
return Nil
}
ENCODERLP serializes B into the Ethereum RLP block format.
Func (b *block) ENCODERLP (w io). Writer) Error {
Return RLP. Encode (W, extblock{
Header:b.header,
Txs:b.transactions,
Uncles:b.uncles,
})
}
This part introduces the data structure and method of chunk head, block body, block, database block, please refer to the source code for details.
Block chain
Core/blockchain.go
After introducing the transaction, block size, chunk, we look at the data structure of the blockchain:
BlockChain represents the canonical chain given a database with a Genesis
Block. The Blockchain manages chain imports, reverts, chain reorganisations.
Importing blocks in to the block chain happens according to the set of rules
Defined by the stage Validator. Processing of blocks is done using the
Processor which processes the included transaction. The validation of the state
Is do in the second part of the Validator. Failing results in aborting of the import.
//
The BlockChain also helps in returning blocks from **any** chain included
In the database as well as blocks that represents the canonical chain. It ' s
Important to note this getblock can return any block and does not need to be
Included in the canonical one where as Getblockbynumber always represents the
Canonical chain.
Type BlockChain struct {
Chainconfig *params. Chainconfig//Chain & Network config literally means the configuration of chains and networks, which are temporarily
CacheConfig *cacheconfig//Cache configuration for pruning
DB Ethdb. Database//Low levels persistent database to store final content in, bottom level db
TRIEGC *prque. Prque//Priority queue mapping block numbers to tries to GC do not know what the role
Gcproc time. Duration//accumulates canonical block processing for trie dumping
HC *headerchain
Rmlogsfeed event. Feed//event. Feeds store subscriber information, Blockchain notify subscribers when an event occurs
Chainfeed event. Feed
Chainsidefeed event. Feed
Chainheadfeed event. Feed
Logsfeed event. Feed
Scope event. Subscriptionscope
Genesisblock *types. Block//Genesis block pointers
Mu sync. Rwmutex//Global mutex for locking chain operations
Chainmu sync. Rwmutex//Blockchain insertion lock
PROCMU sync. Rwmutex//Block processor lock
Checkpoint int//checkpoint counts towards the new checkpoint
Currentblock Atomic. Value//Current Chunk
Currentfastblock Atomic. Value//Current head of the Fast-sync chain (could be above the block chain!)
Statecache state. Database//State database to reuse between imports (contains state cache)
Bodycache *lru. Cache//cache for the most recent block bodies
Bodyrlpcache *lru. Cache//cache for the most recent block bodies in RLP encoded format
Blockcache *lru. Cache//cache for the most recent entire blocks
Futureblocks *lru. Cache//Future blocks is blocks added for later processing
Quit Chan struct{}//Blockchain quit channel
Running int32//running must be called atomically
Procinterrupt must be atomically called
Procinterrupt Int32//interrupt Signaler for block processing
WG Sync. Waitgroup//Chain processing wait Group for shutting down
Engine consensus. Engine//consensus algorithm engines, different algorithms recognize engine interface
Processor Processor//block processor interface, very important data member
Validator Validator//block and State validator interface, very important data member
Vmconfig VMs. Config//virtual machine configuration
Badblocks *lru. Cache/Bad block cache
}
The above is the blockchain data structure, a lot of data members do not understand what role, no problem directly skip, as the analysis of the deepening, we will understand.
Newblockchain returns a fully initialised block chain using information available in the database. It initialises The default Ethereum Validator and Processor.
Func newblockchain (db ethdb. Database, CacheConfig *cacheconfig, Chainconfig *params. Chainconfig, engine consensus. Engine, Vmconfig vm. Config) (*blockchain, error) {
If the cache config is empty, create the object
if CacheConfig = = Nil {
CacheConfig = &cacheconfig{
TRIENODELIMIT:256 * 1024 * 1024,
Trietimelimit:5 * time. Minute,
}
}
Initializing various data members
Bodycache, _: = LRU. New (Bodycachelimit)
Bodyrlpcache, _: = LRU. New (Bodycachelimit)
Blockcache, _: = LRU. New (Blockcachelimit)
Futureblocks, _: = LRU. New (Maxfutureblocks)
Badblocks, _: = LRU. New (Badblocklimit)
To create a block chain object
BC: = &blockchain{
Chainconfig:chainconfig,
Cacheconfig:cacheconfig,
Db:db,
Triegc:prque. New (),
Statecache:state. Newdatabase (DB),
Quit:make (Chan struct{}),
Bodycache:bodycache,
Bodyrlpcache:bodyrlpcache,
Blockcache:blockcache,
Futureblocks:futureblocks,
Engine:engine,
Vmconfig:vmconfig,
Badblocks:badblocks,
}
Creating a blockchain validator and processor, it is important to see these two data members later
BC. Setvalidator (Newblockvalidator (chainconfig, BC, engine))
BC. Setprocessor (Newstateprocessor (chainconfig, BC, engine))
var err error
BC.HC, err = Newheaderchain (db, Chainconfig, Engine, Bc.getprocinterrupt)
If err! = Nil {
return nil, err
}
Get the Genesis block
bc.genesisblock = BC. Getblockbynumber (0)
if Bc.genesisblock = = Nil {
return Nil, errnogenesis
}
If err: = Bc.loadlaststate (); Err! = Nil {
return nil, err
}
Check the current state of the "hashes" and "make sure.
For hash: = Range Badhashes {
If header: = BC. Getheaderbyhash (hash); Header! = Nil {
Get the canonical block corresponding to the offending header ' s number
Headerbynumber: = BC. Getheaderbynumber (header. Number.uint64 ())
Make sure the Headerbynumber (if present) are in our current canonical chain
If headerbynumber! = Nil && headerbynumber.hash () = = header. Hash () {
Log. Error ("Found bad hash, rewinding chain", "number", header.) Number, "hash", header. Parenthash)
Bc. Sethead (header. Number.uint64 ()-1)
Log. Error ("Chain Rewind was successful, resuming normal operation")
}
}
}
Take ownership of the particular state
Go Bc.update ()
return BC, Nil
}
The above is the way to initialize the blockchain, blockchain there are many important methods, because space is limited, here is not one of them, after the analysis needs to come back to see. The following is a simple indicator of several important methods, which can be referenced in the code.
Loadlaststate loads the last known chain state from the database. This method
Assumes the chain manager mutex is held.
Func (BC *blockchain) loadlaststate () Error {
......
}
Sethead rewinds The local chain to a new head. In the case of headers, everythingabove the new head would be deleted and the new one set. In the case of blocks though, the head could be further rewound if block bodies is missing (non-archive nodes after a fast Sync).
Func (BC *blockchain) sethead(head UInt64) error {
......
}
Currentblock retrieves the current head block of the canonical chain. The block is retrieved from the blockchain ' s internal cache.
Func (BC *blockchain) currentblock () *types. Block {
......
}
Setprocessor sets the processor required for making state modifications.
Func (BC *blockchain) Setprocessor(processor processor) {
......
}
Setvalidator sets the validator which is used to validate incoming blocks.
Func (BC *blockchain) setvalidator(Validator validator) {
......
}
Validator returns the current Validator.
Func (BC *blockchain) Validator() Validator {
......
}
Processor returns the current Processor.
Func (BC *blockchain) Processor () Processor {
......
}
Summarize:
This article briefly introduced the Go Ethetheum source code in the transaction, block, blockchain data structure and initialization method, I hope you have some understanding. The next article will cover the trading pool, see how the trade is packaged into chunks, and how chunks are broadcast to the network. Because the author is also rookie, many concepts understand not in-depth, do not understand the concept for a while, analysis in depth will understand.