主页 > 安卓怎么下载imtoken钱包 > 区块链智能合约如何处理和执行交易数据
区块链智能合约如何处理和执行交易数据
一、智能合约的起源
区块链技术自比特币诞生以来就受到了广泛关注。 最初,区块链只是作为记录用户交易的底层账本,不支持用户自定义的其他功能。
为了实现交易,即用户之间转账的功能,比特币设计了一种简单的基于堆栈的脚本语言。 这种语言不支持循环,不具备图灵完备性,仅限于比特币客户端内部使用,只围绕交易功能展开,一般称为“Bitcoin Script”。
如果你查看比特币区块链中的每一笔交易记录,你会发现交易内容其实是一串字节码,也就是Bitcoin Script。 比特币限制了用 Bitcoin Script 编写的交易代码的格式。 这种方式保证了交易的合法性和资金的安全性,但是牺牲了整个系统的可编程性和灵活性。
一般情况下,一套语言可以实现几千种功能。 如果设计一套语言只实现一个功能,那就太可惜了。 或许 Vitalik Buterin 只是发现了脚本语言在区块链中的可能性,于是他把这种语言请到了以太坊的舞台中央,供用户创建和调用,这也成为了以太坊最吸引人的特性——智能合约。
对应比特币的Bitcoin Script,以太坊中脚本语言的名称是EVM语言(Ethereum Virtual Machine Code)。 EVM语言也是一种基于栈的语言,但它是一种图灵完备的语言,而以太坊设计了专门的虚拟机EVM为其提供运行环境,这与Bitcoin Script有明显区别。
2.智能合约的使用以交易为接口
为了明确系统的功能,以太坊扩展了交易的概念。 在比特币中,一笔交易一般是指用户之间的一次转账操作。 在以太坊中,一笔交易除了转账之外,还包括创建或调用智能合约。 因此,可以说EVM语言也是为交易而存在的,只是它服务的交易内容要广泛得多。
让我们先添加一些必要的概念。 以太坊中的账户分为外部账户和合约账户。 外部账户是用户使用的账户,包括用户的私钥、钱包等重要信息; 合约账户用于存储智能合约,通常由外部账户创建。
用户向以太坊区块链发送的每笔交易都包含几个关键字段:“from”表示交易发起方,“to”表示交易接收方,“value”表示交易金额,“data”表示附带信息。
上述三种操作的交易格式如下:
1)普通转账操作:“from A, to B, value C”表示从外部账户A向外部账户B转账,转账金额为C;
2) 智能合约创建操作:“from A, to (empty), value C, data D”表示外部账户A创建智能合约,将C转入合约账户,合约代码为D;
3)智能合约调用操作:“从A,到E,数据F”表示外部账户A调用合约账户E的智能合约,本次调用传递的参数为F。
3 一笔交易的处理流程
让我们来分析一下交易在以太坊区块链中是如何处理和执行的。
这部分在以太坊的源码中写的很清楚,所以我们按照源码中的函数调用流程来说明。 Ethereum Go版源码地址:.
首先,先定位,我们可以找到从core/blockchain.go执行的core/state_processor.go中的Process()方法,在Process()方法中可以找到如下一行代码:
收据, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg)
根据这个函数的名字,我们知道我们找到了执行交易的入口。
3.1 创建EVM虚拟机
浏览core/state_processor.go中的ApplyTransaction()方法,可以发现以下三行关键代码:
context := NewEVMContext(msg, header, bc, 作者)
vmenv := vm.NewEVM(context, statedb, config, cfg)
_, gas, 失败, err := ApplyMessage(vmenv, msg, gp)
第一行新建一个EVM执行上下文,第二行新建一个EVM,第三行使用新建的EVM处理交易消息。 可以看出,在每笔交易执行之前,以太坊都会创建一个EVM虚拟机来负责交易的执行。
继续浏览core/state_transiTIon.go中的ApplyMessage()方法,发现这个方法只有一行代码:
返回 NewStateTransition(evm, msg, gp).TransitionDb()
继续查看core/state_transition.go中的TransitionDb()方法,发现该方法中有一个重要的分支:
如果合同创建{
ret, _, st.gas, vmerr = evm.Create(发件人, st.data, st.gas, st.value)
} 别的 {
st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address()) + 1)
ret, st.gas, vmerr = evm.Call(发件人, st.to(), st.data, st.gas, st.value)
}
这段代码的意思是首先判断是否是创建合约的操作,如果是则调用Create()方法,如果不是则调用Call()方法。 可以看出,交易的三个操作中,创建合约的方法是Create(),调用合约和转账的方法是Call()。
下面我们分别来看一下这两种方法。
3.2 创建智能合约
先看core/vm/evm.go中的Create()方法。 该方法只有两行代码:
contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address()))
return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr)
第一行是根据外部账户地址和nonce值计算出要创建的合约账户地址。 nonce参数用于记录外部账户创建的合约数量。
第二行是将创建的合约账户地址和其他参数传递给同一个文件中的create()方法。
继续查看create()方法可以看到如下三行代码:
随机数 := evm.StateDB.GetNonce(caller.Address())
evm.StateDB.SetNonce(caller.Address(), nonce+1)
contractHash := evm.StateDB.GetCodeHash(合同地址)
第一行是获取想要创建合约的外部账户的nonce值。
第二行是将nonce的值加一写回去,第三行是计算合约地址的哈希值,保证不会发生地址冲突。
计算完合约地址后,可以看到如下一行代码:
evm.StateDB.CreateAccount(合约地址)
这行代码根据合约地址创建合约账户。 创建合约账户后,可以看到如下一行代码:
evm.Transfer(evm.StateDB, caller.Address(), contractAddr, value)¶
创建者从外部账户向合约账户转账,金额为value。 至此,合约账户创建完成。
接下来,您需要创建一个合约对象并运行合约代码:
contract := NewContract(caller, AccountRef(contractAddr), value, gas) contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), 代码)
第一行是创建一个合约对象,第二行是将用户自定义的智能合约代码绑定到合约对象上。
创建合约对象后,使用以下代码行运行合约:
ret, err = run(evm, 合同, 零)
可能有人会疑惑:为什么合约创建后还要运行呢?
这主要有两个原因:第一,系统需要保证合约代码能够正确运行,这样以后的调用才不会出错; 其次,系统需要运行计算消耗的gas量,然后完成外部账户创建合约操作的Deduction。 其实在create()方法中,有检查堆栈深度、创建快照、错误回滚、gas计算等代码。 由于不涉及本文的主要内容,故略过。
3.3 智能合约的传输和调用
然后我们看core/vm/evm.go中的Call()方法,它负责两个交易操作比特币合约交易怎么看盘和数据,合约调用和转账。
不需要在 Call() 方法中创建新地址,只需:
to = AccountRef(地址)
这行代码获取交易接收方的地址。 然后可以看到如下一行代码:
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), 值)
交易发起者将价值金额转移给交易接收者。 下面的代码类似于 Create():
contract := NewContract(来电者, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
第一行创建合约对象,第二行将收件人地址上的智能合约代码绑定到合约对象。 如果是转账操作,收件人地址上没有code,所以绑定的code为空,后面的操作很快就会结束。 绑定完成后,使用run()方法运行合约完成调用:
ret, err = run(evm, 合同, 输入)
在Call()方法中,还有检查栈深、创建快照、出错时滚动、gas计算等代码,留给有兴趣的读者自行阅读。
Create()和Call()中最后的执行调用了core/vm/evm.go中的run()方法,可以找到run()方法:
返回解释器。运行(合同,输入,只读)
接下来找到 core/vm/interpreter.go 中的 Run() 方法。 这个方法就是解释器在EVM中的运行过程。 核心逻辑是循环取出合约的代码,查表分析出具体的opcode,然后查表计算需要消耗的gas数量比特币合约交易怎么看盘和数据,然后调用相应的处理函数要执行的操作码。
核心代码如下:
对于 atomic.LoadInt32(&in.evm.abort) == 0 {
……
op = 合同。 获取操作(个人电脑)
操作 := in.cfg.JumpTable[op]
……
成本,err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize)
……
res, err := operation.execute(&pc, in, contract, mem, 堆栈)
……
}
至此,一笔交易的操作就结束了。
4。结论
综上所述,我们可以理解为以太坊设计的三种交易可以给用户很大的自由度,也可以充分发挥EVM语言及其虚拟机的功能。
用户通过Solidity等语言编写智能合约,然后编译成EVM语言,再打包成交易格式发送到区块链上运行。 得益于这种模式带来的可编程特性,以太坊引领区块链技术进入了2.0时代。
然而,由于 EVM 堆栈深度和 gas 消耗的限制,大多数智能合约都是简单的袖珍程序。 即使这样的方案足以满足现在的需求,未来也必然会面临越来越复杂的交易场景。
如何应对这些场景,需要开发者继续努力。