您的位置:首页 > 其它

MGC TOKEN technical explanation —— Intelligent contract Technology

2019-02-15 15:08 78 查看

MGC Token Smart Contract
The smart contract used by MGC Token is a set of promises defined in digital form, including agreements on which contract participants can execute these commitments. A contract consists of a set of code (the function of the contract) and the data (the state of the contract) and runs on the Ethereum virtual machine.
The Ethereum Virtual Machine (EVM) uses a 256-bit machine code and is a stack-based virtual machine for executing Ethereum smart contracts. Since EVM is designed for the Ethereum system, the Ethereum Account Model is used for value transfer.
What is the ability of the contract code:
Read transaction data.
Read or write the contract’s own storage space.
Read environment variables [block height, hash value, gas]
Send an “internal transaction” to another contract.
The architecture of the blockchain platform:

Solidity
Solidity is a smart contract high-level language that runs on top of the Ethereum Virtual Machine (EVM).
Solidity Language Features:
Its syntax is close to Javascript and is an object-oriented language. But as a decentralized contract that really runs on the web, it has a lot of differences:
The exception mechanism is similar to the atomicity of a transaction. Once an exception occurs, all executions will be retraced, mainly to ensure the atomicity of the contract execution, to avoid data inconsistency in the intermediate state.
The operating environment is on a decentralized network, and it emphasizes the way in which calls or functions are called. Because a simple function call turns into a code on a network, the execution of the code is done using a blockchain on the network, and each state of the data can be stored permanently.
Detailed process of smart contracts
First, the creation of the contract

/ / If the TO is empty, it is a smart contract transaction,
If tx.To() == nil {

/ / This call SendTx->addTx

Signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number())

From, err := types.Sender(signer, tx)

If err != nil {
Return common.Hash{}, err

}
Addr := crypto.CreateAddress(from, tx.Nonce())
log.Info(“Submitted contract creation”, “fullhash”, tx.Hash().Hex(), “contract”, addr.Hex())
}
Tx that other nodes propagate through the network (handler.go:handle()->handleMsg:case msg.Code == TxMsg->AddRemotes):

Func (pool *TxPool) AddRemotes(txs []*types.Transaction) []error {

Return pool.addTxs(txs, false)

}

// addTx enqueues a single transaction into the pool if it is valid.

Func (pool *TxPool) addTx(tx *types.Transaction, local bool) error {

pool.mu.Lock()

Defer pool.mu.Unlock()

// Try to inject the transaction and update any state

Replace, err := pool.add(tx, local)

If err != nil {

Return err

}
// If we added a new transaction, run promotion checks and return

If !replace {

From, _ := types.Sender(pool.signer, tx) // already validated

pool.promoteExecutables([]common.Address{from})

}

Return nil

}

From the previous analysis, we can see that in the end they all called the function “promoExExcutables” to perform pre-execution to determine whether the transaction is qualified. As you can see in addr := crypto.CreateAddress(from, tx.Nonce()), a contract address that was predicted in advance (see analysis below) is created and written to the log.

Only when it is really on the chain, this address will actually be created, as follows:

/core/blockchain.go

// SetReceiptsData computes all the non-consensus fields of the receipts

Func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts types.Receipts) {

For j := 0; j < len(receipts); j++ {

// The transaction hash can be retrieved from the transaction itself

Receipts[j].TxHash = transactions[j].Hash()

// The contract address can be derived from the transaction itself

If transactions[j].To() == nil {

// Deriving the signer is expensive, only do if it’s actually needed

From, _ := types.Sender(signer, transactions[j])

Receipts[j].ContractAddress = crypto.CreateAddress(from, transactions[j].Nonce())

}

}…

}
Look at the same code, if you use the transaction information to view, then when the submission is up, the address is empty, and the address will be available if the package is actually packaged. So whether it is a transaction or a contract, the transaction needs to go through the following process:

Addtx->Judge whether the contract->promoteExecutables

Let’s look at the specific creation process:

// TransitionDb will transition the state by applying the current message and

// returning the result including the the used gas. It returns an error if it

// failed. An error indicates a consensus issue.

Func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bool, err error) {

If err = st.preCheck(); err != nil {

Return

}

Msg := st.msg

Sender := st.from() // err checked in preCheck

Homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber)

contractCreation := msg.To() == nil

// Pay intrinsic gas


Gas, err := IntrinsicGas(st.data, contractCreation, homestead)

If err != nil {

Return nil, 0, false, err

}

If err = st.useGas(gas); err != nil {

Return nil, 0, false, err

}

Var (

Evm = st.evm

// vm errors do not effect consensus and are therefor

// not assigned to err, except for insufficient balance

// error.

Vmerr error

)

If contractCreation {

//Create a contract

Ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value)

} else {

// Increment the nonce for the next transaction

st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+https://blog.csdn.net/taiuu/article/details/1)

Ret, st.gas, vmerr = evm.Call(sender, st.to().Address(), st.data, st.gas, st.value)

}

If vmerr != nil {

log.Debug(“VM returned with error”, “err”, vmerr)

// The only possible consensus-error would be if there wasn’t

// sufficient balance to make the transfer happen. The first

// balance transfer may never fail.

If vmerr == vm.ErrInsufficientBalance {

Return nil, 0, false, vmerr

}

}
st.refundGas()

st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))

Return ret, st.ga 20000 sUsed(), vmerr != nil, err

}

From AddTx—ApplyTransaction-ApplyMessage to the above function is finally a contract created. Need to pay attention to this, AddTx and the previous transaction are not one, don’t confuse. This is from the DeployContract(base.go) function. It calls transact and then SendTransaction(simulated.go)-AddTx.

And called in TransitionDb:

//core/vm/evm.go

// Create creates a new contract using code as deployment code.

Func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {

// Depth check execution. Fail if we’re trying to execute above the

// limit.

If evm.depth > int(params.CallCreateDepth) {

Return nil, common.Address{}, gas, ErrDepth

}
/ / See the following test costs are not enough

If !evm.CanTransfer(evm.StateDB, caller.Address(), value) {

Return nil, common.Address{}, gas, ErrInsufficientBalance

}

// Ensure there’s no existing contract already at the designated address

/ / Set a random value

Nonce := evm.StateDB.GetNonce(caller.Address())

evm.StateDB.SetNonce(caller.Address(), nonce+https://blog.csdn.net/taiuu/article/details/1)

/ / Create a contract address, and the above is not the same, different situations are created separately here is the deployment time

contractAddr = crypto.CreateAddress(caller.Address(), nonce)

contractHash := evm.StateDB.GetCodeHash(contractAddr)

If evm.StateDB.GetNonce(contractAddr) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) {

Return nil, common.Address{}, 0, ErrContractAddressCollision

}

// Create a new account on the state


Snapshot := evm.StateDB.Snapshot()

evm.StateDB.CreateAccount(contractAddr)

If evm.ChainConfig().IsEIPhttps://blog.csdn.net/taiuu/article/details/158(evm.BlockNumber) {

evm.StateDB.SetNonce(contractAddr, https://blog.csdn.net/taiuu/article/details/1)

}

/ / See below the transmission data

evm.Transfer(evm.StateDB, caller.Address(), contractAddr, value)

// initialise a new contract and set the code that is to be used by the

// E The contract is a scoped evmironment for this execution context

// only.

//Create a contract

Contract := NewContract(caller, AccountRef(contractAddr), value, gas)

contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)

If evm.vmConfig.NoRecursion && evm.depth > 0 {

Return nil, contractAddr, gas, nil

}

If evm.vmConfig.Debug && evm.depth == 0 {

evm.vmConfig.Tracer.CaptureStart(caller.Address(), contractAddr, true, code, gas, value)

}

Start := time.Now()
//Pre-execution contract, see below

ret, err = run(evm, contract, nil)

// check whether the max code size has been exceeded

maxCodeSizeExceeded := evm.ChainConfig().IsEIPhttps://blog.csdn.net/taiuu/article/details/158(evm.BlockNumber) && len(ret) > params.MaxCodeSize

// if the contract creation ran successfully and no errors were returned

// calculate the gas required to store the code. If the code could not

// be stored due to not enough gas set an error and let it be handled

// by the error checking condition below.

if err == nil && !maxCodeSizeExceeded {

createDataGas := uint64(len(ret)) * params.CreateDataGas

if contract.UseGas(createDataGas) {

//Update interface code
evm.StateDB.SetCode(contractAddr, ret)

} else {

err = ErrCodeStoreOutOfGas

}

}

// When an error was returned by the EVM or when setting the creation code

// above we revert to the snapshot and consume any gas remaining. Additionally

// when we're in homestead this also counts for code storage gas errors.

if maxCodeSizeExceeded || (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) {

evm.StateDB.RevertToSnapshot(snapshot)

if err != errExecutionReverted {

contract.UseGas(contract.Gas)

}

}

// Assign err if contract code size exceeds the max while the err is still empty.

if maxCodeSizeExceeded && err == nil {

err = errMaxCodeSizeExceeded

}

if evm.vmConfig.Debug && evm.depth == 0 {

evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)

}

return ret, contractAddr, contract.Gas, err

}

It will call core/evm.go

// NewEVMContext creates a new context for use in the EVM.

func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author *common.Address) vm.Context {

// If we don't have an explicit author (i.e. not mining), extract from the header

var beneficiary common.Address

if author == nil {

beneficiary, _ = chain.Engine().Author(header) // Ignore error, we're past header validation

} else {

beneficiary = *author

}

return vm.Context{

CanTransfer: CanTransfer,

Transfer:    Transfer,

GetHash:     GetHashFn(header, chain),

Origin:      msg.From(),

Coinbase:    beneficiary,

BlockNumber: new(big.Int).Set(header.Number),

Time:        new(big.Int).Set(header.Time),

Difficulty:  new(big.Int).Set(header.Difficulty),

GasLimit:    header.GasLimit,

GasPrice:    new(big.Int).Set(msg.GasPrice()),

}

}
// GetHashFn returns a GetHashFunc which retrieves header hashes by number

func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash {

return func(n uint64) common.Hash {

for header := chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-https://blog.csdn.net/taiuu/article/details/1); header != nil; header = chain.GetHeader(header.ParentHash, header.Number.Uint64()-https://blog.csdn.net/taiuu/article/details/1) {

if header.Number.Uint64() == n {

return header.Hash()

}

}

return common.Hash{}

}

}

// CanTransfer checks wether there are enough funds in the address’ account to make a transfer.

// This does not take the necessary gas in to account to make the transfer valid.

func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool {

return db.GetBalance(addr).Cmp(amount) >= 0

}

// Transfer subtracts amount from sender and adds amount to recipient using the given Db

func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {

db.SubBalance(sender, amount)

db.AddBalance(recipient, amount)

}
The next call is the execution part, and finally the interface code is updated:
func (self *StateDB) SetCode(addr common.Address, code []byte) {

stateObject := self.GetOrNewStateObject(addr)

if stateObject != nil {

stateObject.SetCode(crypto.Keccak256Hash(code), code)

}

}

func (self *stateObject) SetCode(codeHash common.Hash, code []byte) {

prevcode := self.Code(self.db.db)

self.db.journal = append(self.db.journal, codeChange{

account:  &self.address,

prevhash: self.CodeHash(),

prevcode: prevcode,

})

self.setCode(codeHash, code)

}

func (self *stateObject) setCode(codeHash common.Hash, code []byte) {

self.code = code

self.data.CodeHash = codeHash[:]

self.dirtyCode = true

if self.onDirty != nil {

self.onDirty(self.Address())

self.onDirty = nil

}

}
A smart contract has been created to date.
Second, the contract call:

The calling interface of EVM is in vm/inferface.go
// CallContext provides a basic interface for the EVM calling conventions. The EVM EVM

// depends on this context being implemented for doing subcalls and initialising new EVM contracts.

type CallContext interface {

// Call another contract

Call(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error)

// Take another's contract code and execute within our own context

CallCode(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error)

// Same as CallCode except sender and value is propagated from parent to child scope

DelegateCall(env *EVM, me ContractRef, addr common.Address, data []byte, gas *big.Int) ([]byte, error)

// Create a new contract

Create(env *EVM, me ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error)

}

Implemented in vm/evm.go

Here is only one analysis:
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {

if evm.vmConfig.NoRecursion && evm.depth > 0 {

return nil, gas, nil

}

// Fail if we're trying to execute above the call depth limit

if evm.depth > int(params.CallCreateDepth) {

return nil, gas, ErrDepth

}

// Fail if we're trying to transfer more than the available balance

if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {

return nil, gas, ErrInsufficientBalance

}

var (

to       = AccountRef(addr)

snapshot = evm.StateDB.Snapshot()

)

if !evm.StateDB.Exist(addr) {

precompiles := PrecompiledContractsHomestead

if evm.ChainConfig().IsByzantium(evm.BlockNumber) {

precompiles = PrecompiledContractsByzantium

}

if precompiles[addr] == nil && evm.ChainConfig().IsEIPhttps://blog.csdn.net/taiuu/article/details/158(evm.BlockNumber) && value.Sign() == 0 {

return nil, gas, nil

}

evm.StateDB.CreateAccount(addr)

}

evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)

// Initialise a new contract and set the code that is to be used by the EVM.

// The contract is a scoped environment for this execution context only.

contract := NewContract(caller, to, value, gas)

contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))

start := time.Now()

// Capture the tracer start/end events in debug mode

if evm.vmConfig.Debug && evm.depth == 0 {

evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)

defer func() { // Lazy evaluation of the parameters

evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)

}()

}

ret, err = run(evm, contract, input)

// When an error was returned by the EVM or when setting the creation code

// above we revert to the snapshot and consume any gas remaining. Additionally

// when we're in homestead this also counts for code storage gas errors.

if err != nil {

evm.StateDB.RevertToSnapshot(snapshot)

if err != errExecutionReverted {

contract.UseGas(contract.Gas)

}

}

return ret, contract.Gas, err

}

What is the difference between Call, CallCode, DelegateCall, and StaticCall? Let’s start with a simple, static call means that the state cannot be modified, similar to the const function, and the delegate call is delegated to someone else. Trouble in the first two Calls and CallCode, the difference between them is that the storage is different, what do you mean? for instance:

A calls Call() B, which uses B’s storage. If A calls CallCode() B, it uses A’s storage. See the related explanation below for details.

// Execute executes the code using the input as call data during the execution.

// It returns the EVM’s return value, the new state and an error if it failed.

//

// Executes sets up a in memory, temporarily, environment for the execution of

// the given code. It enabled the JIT by default and make sure that it’s restored

// to it’s original state afterwards.

func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {

if cfg == nil {

cfg = new(Config)

}

setDefaults(cfg)

if cfg.State == nil {

db, _ := ethdb.NewMemDatabase()

cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db))

}

var (

address = common.StringToAddress("contract")

vmenv   = NewEnv(cfg)

sender  = vm.AccountRef(cfg.Origin)

)

cfg.State.CreateAccount(address)

// set the receiver's (the executing contract) code for execution.

cfg.State.SetCode(address, code)

// Call the code with the given configuration.

ret, _, err := vmenv.Call(

sender,

common.StringToAddress("contract"),

input,

cfg.GasLimit,

cfg.Value,

)

return ret, cfg.State, err

}

// Create executes the code using the EVM create method

func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {

if cfg == nil {

cfg = new(Config)

}

setDefaults(cfg)

if cfg.State == nil {

db, _ := ethdb.NewMemDatabase()

cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db))

}

var (

vmenv  = NewEnv(cfg)

sender = vm.AccountRef(cfg.Origin)

)

// Call the code with the given configuration.

code, address, leftOverGas, err := vmenv.Create(

sender,

input,

cfg.GasLimit,

cfg.Value,

)

return code, address, leftOverGas, err

}

// Call executes the code given by the contract’s address. It will return the

// EVM’s return value or an error if it failed.

//

// Call, unlike Execute, requires a config and also requires the State field to

// be set.

func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) {

setDefaults(cfg)

vmenv := NewEnv(cfg)

sender := cfg.State.GetOrNewStateObject(cfg.Origin)

// Call the code with the given configuration.

ret, leftOverGas, err := vmenv.Call(

sender,

address,

input,

cfg.GasLimit,

cfg.Value,

)

return ret, leftOverGas, err

}
Third, the execution of the contract

The execution of the contract requires an execution machine, that is, Stack, which operates the memory and controls the code’s action flow.
// stack is an object for basic stack operations. Items popped to the stack are

// expected to be changed and modified. stack does not take care of adding newly

// initialised objects.

type Stack struct {

data []*big.Int

}

func newstack() *Stack {

return &Stack{data: make([]*big.Int, 0, https://blog.csdn.net/taiuu/article/details/1024)}

}

func (st *Stack) Data() []*big.Int {

return st.data

}

func (st *Stack) push(d *big.Int) {

// NOTE push limit (https://blog.csdn.net/taiuu/article/details/1024) is checked in baseCheck

//stackItem := new(big.Int).Set(d)

//st.data = append(st.data, stackItem)

st.data = append(st.data, d)

}

func (st *Stack) pushN(ds …*big.Int) {

st.data = append(st.data, ds...)

}

func (st *Stack) pop() (ret *big.Int) {

ret = st.data[len(st.data)-https://blog.csdn.net/taiuu/article/details/1]

st.data = st.data[:len(st.data)-https://blog.csdn.net/taiuu/article/details/1]

return

}

func (st *Stack) len() int {

return len(st.data)

}

func (st *Stack) swap(n int) {

st.data[st.len()-n], st.data[st.len()-https://blog.csdn.net/taiuu/article/details/1] = st.data[st.len()-https://blog.csdn.net/taiuu/article/details/1], st.data[st.len()-n]

}

func (st *Stack) dup(pool *intPool, n int) {

st.push(pool.get().Set(st.data[st.len()-n]))

}

func (st *Stack) peek() *big.Int {

return st.data[st.len()-https://blog.csdn.net/taiuu/article/details/1]

}

// Back returns the n’th item in stack

func (st *Stack) Back(n int) *big.Int {

return st.data[st.len()-n-https://blog.csdn.net/taiuu/article/details/1]

}

func (st *Stack) require(n int) error {

if st.len() < n {

return fmt.Errorf("stack underflow (%d <=> %d)", len(st.data), n)

}

return nil

}

func (st *Stack) Print() {

fmt.Println("### stack ###")

if len(st.data) > 0 {

for i, val := range st.data {

fmt.Printf("%-3d  %v\n", i, val)

}

} else {

fmt.Println("-- empty --")

}

fmt.Println("#############")

}

The memory control it calls:
// Memory implements a simple memory model for the ethereum virtual machine.

type Memory struct {

store       []byte

lastGasCost uint64

}

func NewMemory() *Memory {

return &Memory{}

}

// Set sets offset + size to value

func (m *Memory) Set(offset, size uint64, value []byte) {

// length of store may never be less than offset + size.

// The store should be resized PRIOR to setting the memory

if size > uint64(len(m.store)) {

panic("INVALID memory: store empty")

}

// It's possible the offset is greater than 0 and size equals 0. This is because

// the calcMemSize (common.go) could potentially return 0 when size is zero (NO-OP)

if size > 0 {

copy(m.store[offset:offset+size], value)

}

}

// Resize resizes the memory to size

func (m *Memory) Resize(size uint64) {

if uint64(m.Len()) < size {

m.store = append(m.store, make([]byte, size-uint64(m.Len()))...)

}

}

// Get returns offset + size as a new slice

func (self *Memory) Get(offset, size int64) (cpy []byte) {

if size == 0 {

return nil

}

if len(self.store) > int(offset) {

cpy = make([]byte, size)

copy(cpy, self.store[offset:offset+size])

return

}

return

}

// GetPtr returns the offset + size

func (self *Memory) GetPtr(offset, size int64) []byte {

if size == 0 {

return nil

}

if len(self.store) > int(offset) {

return self.store[offset : offset+size]

}

return nil

}

// Len returns the length of the backing slice

func (m *Memory) Len() int {

return len(m.store)

}

// Data returns the backing slice

func (m *Memory) Data() []byte {

return m.store

}
func (m *Memory) Print() {

fmt.Printf("### mem %d bytes ###\n", len(m.store))

if len(m.store) > 0 {

addr := 0

for i := 0; i+32 <= len(m.store); i += 32 {

fmt.Printf("%03d: % x\n", addr, m.store[i:i+32])

addr++
}
} else {

fmt.Println("-- empty --")
}
fmt.Println("####################")

}
Memory operation (in the instruction instructions.go)
func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {

offset := stack.pop()

val := new(big.Int).SetBytes(memory.Get(offset.Int64(), 32))

stack.push(val)
evm.interpreter.intPool.put(offset)

return nil, nil

}
func opMstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {

// pop value of the stack

mStart, val := stack.pop(), stack.pop()

memory.Set(mStart.Uint64(), 32, math.PaddedBigBytes(val, 32))

evm.interpreter.intPool.put(mStart, val)

return nil, nil

}

func opMstore8(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {

off, val := stack.pop().Int64(), stack.pop().Int64()

memory.store[off] = byte(val & 0xff)

return nil, nil

}
Then it is executed:

Look at run:vm/evm.go

// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.

func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {

if contract.CodeAddr != nil {

//Call the native contract (pre-compiled, no interpreter explained)
precompiles := PrecompiledContractsHomestead

if evm.ChainConfig().IsByzantium(evm.BlockNumber) {

precompiles = PrecompiledContractsByzantium

}

if p := precompiles[*contract.CodeAddr]; p != nil {

return RunPrecompiledContract(p, input, contract)

}

}

//Otherwise call the interpreter to interpret execution
return evm.interpreter.Run(contract, input)

}
It will call:
// RunPrecompiledContract runs and evaluates the output of a precompiled contract.

func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {

gas := p.RequiredGas(input)

if contract.UseGas(gas) {

return p.Run(input)

}

return nil, ErrOutOfGas

}
//Below is one of the four Runs in the Map of the Native Contract.

func (c *ecrecover) Run(input []byte) ([]byte, error) {

const ecRecoverInputLength = https://blog.csdn.net/taiuu/article/details/128

input = common.RightPadBytes(input, ecRecoverInputLength)

// "input" is (hash, v, r, s), each 32 bytes

// but for ecrecover we want (r, s, v)

r := new(big.Int).SetBytes(input[64:96])

s := new(big.Int).SetBytes(input[96:https://blog.csdn.net/taiuu/article/details/128])

v := input[63] - 2https://blog.csdn.net/taiuu/article/details/7

// tighter sig s values input homestead only apply to tx sigs

if !allZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) {

return nil, nil

}

// v needs to be at the end for libsecp256khttps://blog.csdn.net/taiuu/article/details/1

pubKey, err := crypto.Ecrecover(input[:32], append(input[64:https://blog.csdn.net/taiuu/article/details/128], v))

// make sure the public key is a valid one

if err != nil {

return nil, nil

}

// the first byte of pubkey is bitcoin heritage

return common.LeftPadBytes(crypto.Keccak256(pubKey[https://blog.csdn.net/taiuu/article/details/1:])[https://blog.csdn.net/taiuu/article/details/12:], 32), nil

}
If it is not a precompiled contract (can be considered similar to the standard library), call the interpreter
(vm/interpreter.go):

func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err error) {

// Increment the call depth which is restricted to https://blog.csdn.net/taiuu/article/details/1024

in.evm.depth++

defer func() { in.evm.depth-- }()

// Reset the previous call's return data. It's unimportant to preserve the old buffer

// as every returning call will return new data anyway.

in.returnData = nil

// Don't bother with the execution if there's no code.

if len(contract.Code) == 0 {

return nil, nil

}

var (

op    OpCode        // current opcode

mem   = NewMemory() // bound memory

stack = newstack()  // local stack

// For optimisation reason we're using uint64 as the program counter.

// It's theoretically possible to go above 2^64. The YP defines the PC

// to be uint256. Practically much less so feasible.

pc   = uint64(0) // program counter

cost uint64

// copies used by tracer

pcCopy  uint64 // needed for the deferred Tracer

gasCopy uint64 // for Tracer to log gas remaining before execution

logged  bool   // deferred Tracer should ignore already logged steps

)

contract.Input = input

if in.cfg.Debug {

defer func() {

if err != nil {

if !logged {

in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)

} else {

in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)

}

}

}()

}

// The Interpreter main run loop (contextual). This loop runs until either an

// explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during

// the execution of one of the operations or until the done flag is set by the

// parent context.

for atomic.LoadInt32(&in.evm.abort) == 0 {

if in.cfg.Debug {

// Capture pre-execution values for tracing.

logged, pcCopy, gasCopy = false, pc, contract.Gas

}

// Get the operation from the jump table and validate the stack to ensure there are

// enough stack items available to perform the operation.

op = contract.GetOp(pc)

operation := in.cfg.JumpTable[op]

if !operation.valid {

return nil, fmt.Errorf("invalid opcode 0x%x", int(op))

}

if err := operation.validateStack(stack); err != nil {

return nil, err

}

// If the operation is valid, enforce and write restrictions

if err := in.enforceRestrictions(op, operation, stack); err != nil {

return nil, err

}

var memorySize uint64

// calculate the new memory size and expand the memory to fit

// the operation

if operation.memorySize != nil {

memSize, overflow := bigUint64(operation.memorySize(stack))

if overflow {

return nil, errGasUintOverflow

}

// memory is expanded in words of 32 bytes. Gas

// is also calculated in words.

if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow {

return nil, errGasUintOverflow

}

}

if !in.cfg.DisableGasMetering {

// consume the gas and return an error if not enough gas is available.

// cost is explicitly set so that the capture state defer method cas get the proper cost

cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize)

if err != nil || !contract.UseGas(cost) {

return nil, ErrOutOfGas

}

}

if memorySize > 0 {

mem.Resize(memorySize)

}

if in.cfg.Debug {

in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)

logged = true

}

// execute the operation

res, err := operation.execute(&pc, in.evm, contract, mem, stack)

// verifyPool is a build flag. Pool verification makes sure the integrity

// of the integer pool by comparing values to a default value.

if verifyPool {

verifyIntegerPool(in.intPool)

}

// if the operation clears the return data (e.g. it has returning data)

// set the last return to the result of the operation.

if operation.returns {

in.returnData = res

}

switch {

case err != nil:

return nil, err

case operation.reverts:

return res, errExecutionReverted

case operation.halts:

return res, nil

case !operation.jumps:

pc++

}

}

return nil, nil

}
Smart contract introduction concept:

Address: The length of the MGC address, which is 20 bytes in size and https://blog.csdn.net/taiuu/article/details/160 bits, so it can be encoded with a uinthttps://blog.csdn.net/taiuu/article/details/160. The address is the basis of all contracts. All contracts inherit the address object, and you can also call an address string at any time to get the corresponding code. The address of the contract is calculated based on the random number of the account and the hash of the transaction data.
ABI: is a message format of MGC when it is called between contracts or when a message is sent. Is to define the operation function signature, parameter encoding, return result encoding and so on.
Transaction: “Transaction” in the MGC refers to a signature packet that stores messages sent from an external account.
The simple understanding is that as long as the blockchain is written, transactions must occur.
Transaction receipt:
Return value after the transaction occurs
Introduction to contract file structure
Version statement
Pragma solidity ^0.4.https://blog.csdn.net/taiuu/article/details/10;

  1. Reference other source files
    Import “filename”; / / global introduction

  2. State Variables
    Int256 storedData;
    2.Functions (Functions)
    function setData(int256 x) public {
    storedData = x;
    AddMsg(msg.sender, “[in the set() method]”);
    }

    function getData() constant public returns (int256 _ret) {
    return _ret = storedData;
    }

  3. Events
    / / statement of the event
    Event AddMsg(address indexed sender, bytes32 msg);
    / / Use of the event
    Function setData(int256 x) public {
    storedData = x;
    AddMsg(msg.sender, “in the set() method”);
    }

  4. Structure type (Structs Types)
    Contract contract {
    Struct Data {
    Uint deadline;
    Uint amount;
    }
    Data data;
    function set(uint id, uint deadline, uint amount) {
    data.deadline = deadline;
    data.amount = amount;
    }
    }
    5.Function Modifiers

    Similar to hook
    Modifier only_with_at_least(int x) {
    If (x >= 5) {
    x = x+https://blog.csdn.net/taiuu/article/details/10;
    _;
    }
    }
    Contract programming mode COP
    Conditional Programming (COP) is a sub-domain for contract programming, as a hybrid mode for function and imperative programming. COP solves this problem by requiring the programmer to enumerate all the conditions explicitly. The logic becomes flat and there is no conditional state change. Conditional fragments can be properly documented, reused, and inferred based on requirements and implementation. Importantly, COP treats pre-conditions as first-class citizens in programming. Such a model specification guarantees the security of the contract.
    FEATURES
    The function body has no conditional judgment
    example:
    contract Token {
    // The balance of everyone
    mapping (address => uint) public balances;
    // Constructor - we’re a millionaire!
    function Token() {
    balances[msg.sender] = https://blog.csdn.net/taiuu/article/details/1000000;
    }
    // Transfer

    _amount
    tokens of ours to
    _dest
    .
    function transfer(uint _amount, address _dest) {
    balances[msg.sender] -= _amount;
    balances[_dest] += _amount;
    }
    }
    After improvement:
    function transfer(uint _amount, address _dest) {
    if (balances[msg.sender] < _amount)
    return;
    balances[msg.sender] -= _amount;
    balances[_dest] += _amount;
    }
    COP style
    modifier only_with_at_least(uint x) {
    if (balances[msg.sender] >= x) _;
    }

function transfer(uint _amount, address _dest)
only_with_at_least(_amount) {
balances[msg.sender] -= _amount;
balances[_dest] += _amount;
}
Grammar introduction
Reference Types
Indefinite long byte array (bytes)
String
Bytes3 a = “https://blog.csdn.net/taiuu/article/details/123”;
Array
Structure (Struts)
Solidity data location
ype of data location
There are three types of storage location properties for variables: memory, storage, and calldata.
The memory storage location is similar to the memory of our normal program. That is, allocation, that is, use, beyond the scope, can not be accessed, waiting to be recycled.
The storage variable, the data will always exist on the blockchain.
The calldata data location is special. Generally, only external function parameters (excluding return parameters) are forced to be specified as calldata.
Storage - the storage model of state variables
Variables of fixed size (all types except maps, variable-length arrays) are sequentially arranged in order from position 0 in the storage. If multiple variables occupy less than 32 bytes, they will be packed into a single storage slot as much as possible. The specific rules are as follows:
The first item in the storage slot is lower-order aligned (lower-order aligned)
The base type stores only the bytes it actually needs.
If the base type cannot fit into the space left in a slot, it will be placed in the next slot.
Structures and arrays always use a completely new slot and occupy the entire slot (but every item in the structure or within the array still follows the above rules)
Optimization suggestions:
To facilitate EVM optimization, try to consciously sort the variables of the storage and the members of the structure so that they can be packed more closely. For example, in this order, uinthttps://blog.csdn.net/taiuu/article/details/128, uinthttps://blog.csdn.net/taiuu/article/details/128, uint256, instead of uinthttps://blog.csdn.net/taiuu/article/details/128, uint256, uinthttps://blog.csdn.net/taiuu/article/details/128. Because the latter will occupy three slots.
Memory - Layout in Memory
Solidity reserves three slots of 32 bytes size:
0-64: scratch space of the hash method (scratch space)
64-96: Current allocated memory size (also known as free memory pointer)
The scratch space can be used between statements (such as in inline compilation)
Solidity always creates a new object at the location of the free memory pointer, and the corresponding memory is never released (maybe this will change in the future).
Some operations in Solidity require more than 64 bytes of temporary space, which will exceed the reserved scratch space. They will be assigned to the location of the free memory pointer, but due to their own characteristics, the life cycle is relatively short, and the pointer itself can not be updated, the memory may or may not be zerod out. Therefore, you should not think that free memory must be zeroed out.
Example
Address
The length of the MGC address is 20 bytes in size and https://blog.csdn.net/taiuu/article/details/160 bits, so it can be encoded with a uinthttps://blog.csdn.net/taiuu/article/details/160. The address is the basis of all contracts. All contracts inherit the address object, and you can also call an address string at any time to get the corresponding code.
Event
Event AddMsg(address indexed sender, bytes32 msg);
This line of code declares an “event”. The client (also applicable to the server application) can listen for these events triggered by the blockchain with very low overhead. The event is a handy tool that uses the built-in functionality of the EVM log. In the DAPP interface, it can in turn call the Javascript listener event callback.
var event = instance.AddMsg({}, function(error, result) {
if (!error) {
var msg = "AddMsg: " + utils.hex2a(result.args.msg) + " from "
console.log(msg);
return;
} else {
console.log(‘it error’)
}
});
Events can be inherited in contracts, and when called, triggers the parameter storage in the transaction log (a special data structure on a blockchain). These logs are associated with the contract’s address and merged into the blockchain, as long as the block is accessible (at least Frontier, Homestead is like this, but Serenity may be the same). Logs and events are not directly accessible within the contract, even if the contract is created.
The log location is in nodedir0/log and can be verified with a special type.
Array
An array is a fixed length or a variable length array. There is a length attribute indicating the current array length.
Bytes: similar to byte[], a byte array of dynamic length
String: similar to bytes, dynamic length UTF-8 encoded character type
Byteshttps://blog.csdn.net/taiuu/article/details/1~bytes32
Generally use fixed length byteshttps://blog.csdn.net/taiuu/article/details/1~bytes32. When you know the length of the string, you can save more space when you specify the length. Create an array
Literal uint[] memory a = []
New uint[] memory a = new uint;
example:
Pragma solidity ^0.4.0;
Contract SimpleStartDemo{
Uint[] stateVar;
Function f(){
/ / Define a variable length array
Uint[] memory memVar;

/ / Can not be used before using new initialization
//VM Exception: invalid opcode
//memVar [0] = https://blog.csdn.net/taiuu/article/details/100;

/ / Initialize a memory variable length array by new
memVar = new uint[](2);

/ / Can not be used before using new initialization
//VM Exception: invalid opcode
//stateVar[0] = https://blog.csdn.net/taiuu/article/details/1;

/ / Initialize a variable length array of storage by new
stateVar = new uint[](2);
stateVar[0] = https://blog.csdn.net/taiuu/article/details/1;

}
}
Array properties and methods
Length attribute
Storage variable length array can modify length
Memory variable length array is not able to modify length
Push method
Storage variable length array can use the push method
Bytes can use the push method
example:
Pragma solidity ^0.4.2;
Contract SimpleStartDemo {
Uint[] stateVar;
Function f() returns (uint){
/ / Use before the element is initialized
stateVar.push(https://blog.csdn.net/taiuu/article/details/1);
stateVar = new uint;
stateVar[0] = 0;
/ / Automatic expansion length
Uint pusharr = stateVar.push(https://blog.csdn.net/taiuu/article/details/1);
Uint len = stateVar.length;
/ / Does not support memory
//Member “push” is not available in uint256[] memory outside of storage.
//uint[] memory memVar = new uint;
https://memVar.push(https://blog.csdn.net/taiuu/article/details/1);
Return len;
}
}
Subscript: similar to other languages
Memory array
If the Memory array is passed as a function argument, it can only support type types that ABI can support. The Memory array is an attribute that cannot modify the size of the modified array.
example:
Pragma solidity ^0.4.2;
Contract SimpleStartDemo {
Function f() {
/ / Create a memory array
Uint[] memory a = new uint;
/ / can not modify the length
//Error: Expression has to be an lvalue.
https://a.length = https://blog.csdn.net/taiuu/article/details/100;
}
//storage
Uint[] b;

Function g(){
b = new uint;
/ / Can modify the array of storage
B.length = https://blog.csdn.net/taiuu/article/details/10;
b[9] = https://blog.csdn.net/taiuu/article/details/100;
}

}
EVM restrictions
Due to the limitations of EVM, dynamic arrays and multidimensional arrays cannot be directly returned by external functions.
The stroage array cannot be returned directly, and needs to be converted to a memory type return.
//Data layer data
Struct rate {
Int keyhttps://blog.csdn.net/taiuu/article/details/1;
Int unit;
Uint[3] exDataArr;
Bytes32[3] exDataStr;
}

Mapping(int =>Rate) Rates;
Function getRate(int keyhttps://blog.csdn.net/taiuu/article/details/1) public constant returns(int,uint[3],bytes32[3]) {
Uint[3] memory exDataInt = Rates[keyhttps://blog.csdn.net/taiuu/article/details/1].exDataArr;
Bytes32[3] memory exDataStr = Rates[keyhttps://blog.csdn.net/taiuu/article/details/1].exDataStr;
Return (Rates[keyhttps://blog.csdn.net/taiuu/article/details/1].unit,exDataInt,exDataStr);
}

Business scene
function
Function () {internal (default)|external} constant [returns ()]
Function internal and external
example:
Pragma solidity ^0.4.5;

Contract FuntionTest{
Function internalFunc() internal{}

Function externalFunc() external{}

Function callFunc(){
/ / Directly use the internal way to call
internalFunc();

/ / Can not call an external function internally, will report a compilation error.
//Error: Undeclared identifier.
//externalFunc();

/ / Can not call an `internal` by `external`
//Member "internalFunc" not found or not visible after argument-dependent lookup in contract FuntionTest
//this.internalFunc();

/ / Use `this` to call an external function in the form of `external`
this.externalFunc();
}

}
Contract FunctionTesthttps://blog.csdn.net/taiuu/article/details/1{
Function externalCall(FuntionTest ft){
/ / call the external function of another contract
ft.externalFunc();

/ / can not call the internal function of another contract
//Error: Member "internalFunc" not found or not visible after argument-dependent lookup in contract FuntionTest
//ft.internalFunc();
}

}
The access function has external (external) visibility. If you access it internally, such as direct access, you can use it directly as a variable, but if you use an external method to access it, such as via this., then it must be done by function. transfer.
example:
pragma solidity ^0.4.2;

contract SimpleStartDemo {
uint public c = https://blog.csdn.net/taiuu/article/details/10;

function accessInternal() returns (uint){
return c;
}

function accessExternal() returns (uint){
return this.c();
}
}

Function call

Internal calls do not create an EVM call, also called a message call.
An external call to create an EVM call initiates a message call.
Function Modifiers
Modifiers can be used to easily change the behavior of a function. For example, to check some precondition before the function is executed. A modifier is a contract property that can be inherited and can also be overridden by a derived contract.
example:
pragma solidity ^0.4.2;

contract SimpleStartDemo {
int256 storedData;
event AddMsg(address indexed sender, bytes32 msg);

modifier only_with_at_least(int x) {
if (x >= 5) {
x = x+https://blog.csdn.net/taiuu/article/details/10;
_;
}
}
function setData(int256 x) public only_with_at_least(x){
storedData = x;
AddMsg(msg.sender, "[in the set() method]");
}
}

Contract constructor, function of the same name is optional, only one constructor can be used, and overloading is not supported.
Constant
Functions can also be declared as constants, and such functions promise to not modify any state on the blockchain. When you get data from the chain, the get function will be added with constant.
Inheritance
Solidity supports multiple inheritance by copying code that includes polymorphism.
Father
pragma solidity ^0.4.4;

contract Meta {
string  public name;
string  public abi;
address metaAddress;

function Meta(string n,string a){
name=n;
abi=a;
}

function getMeta()public constant returns(string,string,address){
return (name,abi,metaAddress);
}

function setMetaAddress(address meta) public {
metaAddress=meta;
}
}

Subclass
pragma solidity ^0.4.4;

import "Meta.sol";
contract Demo is Meta{
bytes32 public orgID;

function Demo (string n,string abi,bytes32 id) Meta(n,abi)
{
orgID = id;
}
}

The simplest contract structure

limit
Based on EVM restrictions, dynamic content cannot be returned via external functions:
please keep in mind
https://blog.csdn.net/taiuu/article/details/1.Fail as early and loudly as possible
2.Favor pull over push payments
3.Order your function code: conditions, actions, interactions
4.Be aware of platform limits
5.Write tests
6.Fault tolerance and Automatic bug bounties
https://blog.csdn.net/taiuu/article/details/7.Limit the amount of funds deposited
8.Write simple and modular code
9.Don’t write all your code from scratch
https://blog.csdn.net/taiuu/article/details/10.Timestamp dependency: Do not use timestamps in critical parts of the code, because miners can manipulate them
https://blog.csdn.net/taiuu/article/details/1https://blog.csdn.net/taiuu/article/details/1.Call stack depth limit: Don’t use recursion, and be aware that any call can fail if stack depth limit is reached
https://blog.csdn.net/taiuu/article/details/12.Reentrancy: Do not perform external calls in contracts. If you do, ensure that they are the very last thing you do
The pain point of the language itself
ABI supports a limited number of types, it is difficult to return complex structure types; Deep Stack problem, difficult to debug, can only rely on event log, the contract debugging; contract call contract can only use fixed-length array.
Contract structure
Contract structure layering
The simplest architecture
The structure of the contract is divided into two layers of data contracts and logical contracts.
Data contract [model]
Logical contract [controller]
The reason for this stratification is to facilitate the upgrade of the late contract.
Advantage
Everyone uses it, it’s easy to use, and the ecology is more comprehensive than other contractual frameworks.
Features
One-click initial development project (including configuration)
Contract compilation
Contract deployment
Contract test
Contract debug [can learn from]
Related terms:
MGC TOKEN uses the Ethereum contract, and the Ethereum contract code is written in a low-level stack-based bytecode language called Ethereum Virtual Machine Code or EVM Code. The code consists of a series of bytes, each of which represents an operation.
UTXO: The “state” of the Bitcoin system is a collection of all bitcoins that have been dug up (technically referred to as “unspent transaction outputs or UTXO”). Each UTXO has a face value and owner (defined by an address of 20 bytes that is essentially a cryptographic public key [https://blog.csdn.net/taiuu/article/details/1]). A transaction includes one or more inputs and one or more outputs. Each input contains a reference to an existing UTXO and a cryptographic signature created by the private key corresponding to the owner’s address. Each output contains a new UTXO that is added to the state.
Blockchain: The blockchain originated from the bitcoin of Nakamoto. As the underlying technology of Bitcoin, it is essentially a decentralized database. It refers to the technical solution of collectively maintaining a reliable database through decentralization and trust.
MGC TOKEN smart contract call source code analysis
Smart contract overall flow chart

https://blog.csdn.net/taiuu/article/details/1.API initiates smart contract execution transaction
On a deployed smart contract, a contract call can be initiated. Each new contract call will generate a new transaction, and the Ethereum blockchain network will need to process the transaction upwind event. The following are the two main data structures used in the transaction initiation process:
https://blog.csdn.net/taiuu/article/details/1.https://blog.csdn.net/taiuu/article/details/1 Related data structure
The client side transmission data structure shows:
/*
file: ethapi\api.go
*/type SendTxArgs struct {
From common.Address

json:"from"

To *common.Address
json:"to"

Gas *hexutil.Uint64
json:"gas"

GasPrice *hexutil.Big
json:"gasPrice"

Value *hexutil.Big
json:"value"

Nonce *hexutil.Uint64
json:"nonce"

Data *hexutil.Bytes
json:"data"

Input hexutil.Bytes
json:"input"

}
MGC TOKEN transaction data structure display:
/
file: core\types\transaction.go
*/type Transaction struct {
data txdata
hash atomic.Value
size atomic.Value
from atomic.Value
}
type txdata struct {
AccountNonce uint64
json:"nonce" gencodec:"required"

Price *big.Int
json:"gasPrice" gencodec:"required"

GasLimit uint64
json:"gas" gencodec:"required"

Recipient *common.Address
json:"to" rlp:"nil"

Amount *big.Int
json:"value" gencodec:"required"

Payload []byte
json:"input" gencodec:"required"

V *big.Int `json:"v" gencodec:"required"`
R *big.Int `json:"r" gencodec:"required"`
S *big.Int `json:"s" gencodec:"required"`

Hash *common.Hash `json:"hash" rlp:"-"`

}
https://blog.csdn.net/taiuu/article/details/1.2 Flow chart details

Ethapi/api.go recognizes that this is a transaction send request, calling the SendTransaction() function to further send the message to the underlying. First, the function checks the legitimacy of the sending transaction account and sets a series of initial values for the transaction, such as gas, nonce, and so on. After the transaction information is filled, put it in the transaction pool and wait for the next step.
https://blog.csdn.net/taiuu/article/details/1a. Create a Transaction based on the incoming information. Note that there is a judgment statement here, depending on whether To has a value to determine whether the contract is created or called.
If args.To == nil { // When the contract is called, here to is not empty
Return types.NewContractCreation(…)
}return types.NewTransaction(…)
https://blog.csdn.net/taiuu/article/details/1b. SignTx() signs the transaction using the transaction initiator information. There is a concept of wallet here, and “USB” is mentioned many times in the official source code comment. After searching online, I know that this is the hardware wallet launched by Ethereum. It is a hardware device that securely stores private keys and connects to the computer through USB. When trading, when sending a transaction to the MGC TOKEN blockchain network, you need to use the private key of the hardware wallet for transaction signature. The following quotes a description of the hardware wallet:
Ledger’s hardware wallet is built around “secure components” or security chips. This is the same technology used in chips and PIN payments or SIM cards. These chips provide protection against physical attacks and greatly enhance the security of the private key. Our R&D staff comes from the security industry (Gemalto Gemalto, Oberthur Obert, a global leader in digital security), and we have extensive experience in smart cards and secure embedded operating systems.
Go var chainID big.Int if config := sbChainConfig(); config.IsEIPhttps://blog.csdn.net/taiuu/article/details/155(sbCurrentBlock().Number()) { chainID = config.ChainId } signed, err := wallet.SignTx(account, tx, chainID )
If it is detected that the Ethereum software is not running, it will directly feedback the empty transaction information.
Go / file: accouts\usbwallet\ledger.go */ if w.offline() { return common.Address{}, nil, accounts.ErrWalletClosed }
https://blog.csdn.net/taiuu/article/details/1c. submitTransaction() Pushes the transaction into the trading pool and waits for the next step.
Go func submitTransaction(…) (common.Hash, error) { if err := b.SendTx(ctx, tx); err != nil { return common.Hash{}, err } if tx.To() = = nil { … addr := crypto.CreateAddress(from, tx.Nonce()) log.Info(… “contract”, addr.Hex()) } … return tx.Hash(), nil }
The pooling operation will call the following key functions. The trading pool is divided into two transaction lists. The pending transaction stores executable transactions, and the queue stores transactions that are temporarily unexecutable in the queue. They can convert each other. Before entering the pool, pool.validateTx() will check the transaction signature. For a legitimate new transaction, pool.enqueueTx() will put it into the queue list first, then promoteExecutables() will move it into pending according to the condition.

/*
file: core\tx_pool.go
*/
func (pool *TxPool) addTx(...) error {
...
replace, err := pool.add(tx, local)
if err != nil {
return err
}

if !replace {
from, _ := types.Sender(pool.signer, tx)
pool.promoteExecutables([]common.Address{from})
}
return nil

}
3.Worker transaction packaged out
![在这里插入图片描述](https://img-blog.csdnimg.cn/20https://blog.csdn.net/taiuu/article/details/1902https://blog.csdn.net/taiuu/article/details/15https://blog.csdn.net/taiuu/article/details/1506389https://blog.csdn.net/taiuu/article/details/12.?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_https://blog.csdn.net/taiuu/article/details/10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0Lhttps://blog.csdn.net/taiuu/article/details/1RBSVVV,size_https://blog.csdn.net/taiuu/article/details/16,color_FFFFFF,t_https://blog.csdn.net/taiuu/article/details/70)
As the trading pool grows, the miner service completes the transaction packaging and export operations according to certain conditions. The generated blocks will be propagated through the P2P service in the network.
(details to be completed)
3.Blockchain block winding
3.https://blog.csdn.net/taiuu/article/details/1 Overview
After receiving the transmitted block on the network, trigger the InsertChain() function of blockchain.go to enter the processing of the block: Blockchain check-> Block header verification->Block verification->Transaction processing -> Status Verification -> Block Winding.
/*
file: core\blockchain.go
*/func (bc *BlockChain) insertChain(chain types.Blocks) (...) {
for i := https://blog.csdn.net/taiuu/article/details/1; i < len(chain); i++ {
if chain[i].NumberU64() != chain[i-https://blog.csdn.net/taiuu/article/details/1].NumberU64()+https://blog.csdn.net/taiuu/article/details/1 || chain[i].ParentHash() != chain[i-https://blog.csdn.net/taiuu/article/details/1].Hash() {
...
return 0, nil, nil, ...
}
}
...
abort, results := bc.engine.VerifyHeaders(...)
...
for i, block := range chain {
...
err := <-results
if err == nil {
err = bc.Validator().ValidateBody(block)
}
...
state, err := state.New(parent.Root(), bc.stateCache)
if err != nil {
return i, events, coalescedLogs, err
}

receipts, logs, usedGas, err := bc.processor.Process(...)
if err != nil {
bc.reportBlock(block, receipts, err)
return i, events, coalescedLogs, err
}

err = bc.Validator().ValidateState(...)
if err != nil {
bc.reportBlock(block, receipts, err)
return i, events, coalescedLogs, err
}

status, err := bc.WriteBlockWithState(...)
if err != nil {
return i, events, coalescedLogs, err
}
switch status {
case CanonStatTy:
...
case SideStatTy:
...
}
...
return 0, events, coalescedLogs, nil
}
Message data structure display
type Message struct {
to         *common.Address
from       common.Address
nonce      uint64
amount     *big.Int
gasLimit   uint64
gasPrice   *big.Int
data       []byte
checkNonce bool
}
3.2 Flowchart details
![在这里插入图片描述](https://img-blog.csdnimg.cn/20https://blog.csdn.net/taiuu/article/details/1902https://blog.csdn.net/taiuu/article/details/15https://blog.csdn.net/taiuu/article/details/15065385.?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_https://blog.csdn.net/taiuu/article/details/10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0Lhttps://blog.csdn.net/taiuu/article/details/1RBSVVV,size_https://blog.csdn.net/taiuu/article/details/16,color_FFFFFF,t_https://blog.csdn.net/taiuu/article/details/70)
The transaction process calls state_processer.go's Process() function to process all transactions in the block one by one.
/*
file: core\state_processor.go
*/func (p *StateProcessor) Process(...) (types.Receipts, []*types.Log, uint64, error) {
...
for i, tx := range block.Transactions() {
statedb.Prepare(tx.Hash(), block.Hash(), i)
receipt, _, err := ApplyTransaction(...)
if err != nil {
return nil, nil, 0, err
}
receipts = append(receipts, receipt)
allLogs = append(allLogs, receipt.Logs...)
}

p.engine.Finalize(...)

return receipts, allLogs, *usedGas, nil
}
2a. The AsMessage() function converts a Transaction data structure to a Message data structure
Msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
If err != nil {
Return nil, 0, err
}
2b. newEvm() Creates a virtual machine environment for the execution of the contract.
Context := NewEVMContext(msg, header, bc, author)
Vmenv := vm.NewEVM(context, statedb, config, cfg)
2c. ApplyMessage() Creates a new state change instance and calls state_transition.go's TransitionDb() function to apply the contract code to this instance, and a substantial state transition record occurs. TransitionDb() first performs an entry check of the transaction execution to confirm that nonce, gas is legally available; then select either Create() or Call() depending on whether it is a contract creation or a contract call. In contract deployment, Call() is called here.
/*
file: core\state_transition.go
*/func (st *StateTransition) TransitionDb() () {
if err = st.preCheck(); err != nil {
return
}
...
contractCreation := msg.To() == nil
...
if contractCreation {
ret, _, st.gas, vmerr = evm.Create(...)
} else {
st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+https://blog.csdn.net/taiuu/article/details/1)
ret, st.gas, vmerr = evm.Call(...)  //Contract call
}
...
return ret, st.gasUsed(), vmerr != nil, err
}
The following is the process that goes to the core of the contract call, which is done by the call() of core\vm\evm.go. Before the actual call, some basic legality checks will be done, such as whether the balance is sufficient for transfer, account legality, etc. Note that if the object account does not exist here, a new account will be created internally for the account address. The run() function will execute the contract code, and the third parameter is nil, which means that no function in the contract is called, just initialization.
Tips: In MGC TOKEN, when the account inquiry function and the transfer function are performed, the contract is called transaction. But we know that the query action does not need to be wound up, and the transfer is only needed. MGC TOKEN designed this control in the preparation of smart contracts, controlled by the sol language function modifier keywords.
The role of the constant, view, and pure function modifiers in Solidity is to tell the compiler that the function does not change/do not read the state variables, so the function execution can consume no gas, because no miners are needed to verify. Prior to Solidity v4.https://blog.csdn.net/taiuu/article/details/1https://blog.csdn.net/taiuu/article/details/7, only constant, subsequent versions split constant into view and pure. The role of view is exactly the same as constant, you can read the state variable but can't change it; the pure is more strict, the pure modified function can't change and can't read the state variable, the intelligent operation function internal variable, otherwise the compiler can't.
/*
![在这里插入图片描述](https://img-blog.csdnimg.cn/20https://blog.csdn.net/taiuu/article/details/1902https://blog.csdn.net/taiuu/article/details/15https://blog.csdn.net/taiuu/article/details/1508https://blog.csdn.net/taiuu/article/details/1833.?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_https://blog.csdn.net/taiuu/article/details/10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0Lhttps://blog.csdn.net/taiuu/article/details/1RBSVVV,size_https://blog.csdn.net/taiuu/article/details/16,color_FFFFFF,t_https://blog.csdn.net/taiuu/article/details/70)
file: core\vm\evm.go
*/func (evm *EVM) Call(...) (...) {
if evm.vmConfig.NoRecursion && evm.depth > 0 {
return nil, gas, nil
}
if evm.depth > int(params.CallCreateDepth) {
return nil, gas, ErrDepth
}
// Is the balance sufficient?
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
return nil, gas, ErrInsufficientBalance
}

var (
to       = AccountRef(addr)
snapshot = evm.StateDB.Snapshot()
)
if !evm.StateDB.Exist(addr) {
...
//If the other party's address has no account, create it.
evm.StateDB.CreateAccount(addr)
}

// Perform a transfer action at the DB level
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
// Create a temporary contract for the current contract execution
Contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
...

ret, err = run(evm, contract, input)
// Call failed, rollback data based on snapshot
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
...
}
return ret, contract.Gas, err
}
The blockBlockWithState() of blockchain.go will be written to the block and receipt using 3a. WriteBlock() 3b. WriteReceipts() of accessors_chain.go.
4.API Get Receipt
4.https://blog.csdn.net/taiuu/article/details/1 Overview

In the above process, after the transaction is executed, the requester will not be explicitly replied to the specific situation of any transaction execution. In the Ethereum blockchain network, the requester is required to explicitly request a transaction receipt to confirm the execution of the transaction. From the third step in the previous section, the transaction execution receipt has been written into the db, and the requesting side has to do so to obtain the transaction receipt request.
4.2 Flowchart details

Ethapi/api.go recognizes that this is a transaction send request and calls the GetTransactionReceipt() function to further send the message to the underlying. If the contract address in the receipt is not all 0, it is considered a contract deployment process, filling in the contract address in the transaction to the receipt for use by the requesting end.
4a. Call the ReadTransaction() function to get the basic information of the transaction.
4b. Call the GetReceipts() function to get the transaction receipt, which internally calls the ReadHeadNumber() and ReadReceipts() functions to assist the operation.
/*
file: ethapi/api.go
*/func (s *PublicTransactionPoolAPI) GetTransactionReceipt(...) (...) {
tx, blockHash, blockNumber, index := rawdb.ReadTransaction(...)
...
receipts, err := s.b.GetReceipts(ctx, blockHash)
if err != nil {
return nil, err
}
...
if receipt.ContractAddress != (common.Address{}) {
fields["contractAddress"] = receipt.ContractAddress
}
return fields, nil
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐