主页 > 安卓怎么下载imtoken钱包 > 区块链智能合约如何处理和执行交易数据

区块链智能合约如何处理和执行交易数据

安卓怎么下载imtoken钱包 2023-04-20 07:52:45

一、智能合约的起源

区块链技术自比特币诞生以来就受到了广泛关注。 最初,区块链只是作为记录用户交易的底层账本,不支持用户自定义的其他功能。

为了实现交易,即用户之间转账的功能,比特币设计了一种简单的基于堆栈的脚本语言。 这种语言不支持循环,不具备图灵完备性,仅限于比特币客户端内部使用,只围绕交易功能展开,一般称为“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 消耗的限制,大多数智能合约都是简单的袖珍程序。 即使这样的方案足以满足现在的需求,未来也必然会面临越来越复杂的交易场景。

如何应对这些场景,需要开发者继续努力。