《深入掌握以太坊核心技术》--07-以太坊交易

交易的本质

  • 交易是由外部拥有的账户发起的签名信息,由以太坊网络传输,并被序列化后记录在以太坊区块链上。
  • 交易是唯一可以触发状态更改或导致合约在EVM中执行的事务。
  • 以太坊是一个全局单例状态机,交易是唯一可以改变其状态的东西。(单例:一个时间段,只保留一个状态,单实例)
  • 合约不是自己运行的,以太坊也不会“在后台”运行。以太坊上的一切变化都始于交易。

交易的数据结构

交易是包含以下数据的序列化二进制消息:

  • nonce:由发起人EOA发出的序列号,用于防止交易消息重播(防止重放攻击,让交易唯一化,)
  • gas price:交易发起人愿意支付的gas单价(单位wei)
    -start gas(gasLimit):交易发起人愿意支付的最大gas数量
  • to:目的以太坊地址
  • value:要发送到目的地的以太数量
  • data:可变长度二进制数据负载(payload)
  • r、s、v:发起人EOA的ECDSA签名的三个组成部分(椭圆曲线签名)
  • 交易消息的结构使用递归长度前缀(RLP)编码方案进行序列化,该方案专为在以太坊中准确和字节完美的数据序列化而创建

交易中的nonce

  • 以太坊黄皮书中的定义:一个标量值,等于从这个地址发送的交易数,或者对于关联code的账户来说,是这个账户创建合约的数量。
  • nonce不会明确存储为区块链中账户状态的一部分。相反,它是通过计算发送地址的已确认交易的数量来动态计算的。
  • nonce值还用于防止错误计算账户余额。nonce强制来自任何地址的交易按顺序处理,没有间隔,无论节点接收他们的顺序如何。
  • 使用nonce确保所有节点计算相同的余额和正确的序列交易,等同于用于防止比特币双花攻击的机制。但是由于以太坊跟踪账户余额并且不单独跟踪UTXO,因此只有在错误地计算账户余额时才会发生双重支付。nonce机制可以防止这种情况发生。

在以太坊和其他一些区块链平台中,每笔交易都有一个与发送者账户相关联的 nonce 值。这个 nonce 值确保了交易的唯一性,并防止同一笔交易被重复执行或重放到区块链网络中。发送交易时,需要指定正确的 nonce 值,以确保交易被正确地排序和执行。Nonce 在防止重放攻击中发挥了重要作用,特别是在交易的签名和执行过程中。由于每个交易都需要正确的 nonce 值才能被区块链网络接受和执行,攻击者无法重放之前的交易,因为它们的 nonce 值将会与当前状态不匹配,从而导致交易被拒绝或执行失败。因此,nonce 可以有效地防止重放攻击。
重放攻击
假设在以太坊网络上发生了硬分叉,分成了两个链,称为链 A 和链 B。如果某个用户在硬分叉之前向地址 X 发送了一笔交易,那么在分叉后,这笔交易可能会在链 A 和链 B 上都存在。攻击者可以在其中一个链上重新播放这笔交易,从而在该链上产生相同的效果,例如转移资金或执行智能合约。

并发和nonce

  • 以太坊是一个允许操作(节点,客户端,DAppS)并发的系统,但强制执行单例状态。例如,出块的时候只有一个系统状态
  • 假如我们有多个独立的钱包应用或客户端,比如MetaMask和 Geth,它们可以使用相同的地址生成交易。如果我们希望它们都够同时发送交易,该怎么设置交易的nonce呢?

1.用一台服务器为各个应用分配nonce,先来先服务–可能出现单点故障,并且失败的交易会将后续交易阻塞。(单点故障:该服务器失效,问题就大了,同时也中心化了)
2.生成交易后不分配nonce,也不签名,而是把它放入一个队列等待,另起一个节点跟踪nonce并签名交易。同样会有单点故障的可能,而且跟踪nonce和签名的节点是无法实现真正并发的。(引入Nonce导致并发性下降)

交易中的Gas

  • 当由于交易或消息触发EVM运行时,每个指令都会在网络的每个节点上执行。这具有成本:对于每个执行的操作,都存在固定的成本,我们把这个成本用一定量的gas表示。
  • gas是由交易发起人需要为EVM上的每项操作支付的成本名称。发起交易时,我们需要从执行代码的矿工那里用以太币购买gas。
  • gas与消耗的系统资源对应,这是具有自然成本的。因此在设计上gas和ether有意地解耦,消耗的gas数量代表了对资源的占用,而对应的交易费用则还跟gas对以太的单价有关。这两者是由自由市场调节的:gas的价格实际上是由矿工决定的,他们可以拒绝处理gas价格低于最低限额的交易。我们不需要专门购买gas,只需要将以太币添加进账户即可,客户端在发送交易时会自动用以太币购买gas。

gas的计算

  • 发起交易时的 gas limit 并不是要支付的 gas 数量,而只是给定了一个消耗gas 的上限,相当于“押金
  • 实际支付的 gas数量是执行过程中消耗的gas(gasUsed),gas limit中剩余的部分会返回给发送人
  • 最终支付的 gas 费用是gasUsed 对应的以太币费用,单价由设定的gasPrice 而定
  • 最终支付费用totalCost=gasPrice*gasUsed
  • totalCost会作为交易手续费(Txfee)支付给矿工

在geth控制台中,使用eth.estimateGas预估需要的gas

eth.estimateGas({from: eth.accounts[0], to:eth.accounts[1], value: 10000000000000000});
// 带有需要执行的data的交易
eth.estimateGas({from: eth.accounts[0], to:eth.accounts[1], value: 10000000000000000, data:'0x0000'});

交易的接收者to

  • 交易接收者在to字段指定,是一个20字节的以太坊地址。地址可以是EOA或者合约地址。
  • 以太坊没有进一步验证,任何20字节的值都被认为是有效的。如果20字节值对应于没有相应私钥的地址,或者不存在的合约,则该交易仍然有效。以太坊无法知道地址是否是从公钥正确派生的。
  • 如果将交易发送到无效地址,将销毁发送的以太,使其永远无法访问
  • 验证接收人地址是否有效的工作,应该在用户界面一层完成

交易的value和data

  • 交易的主要有效负载包含在两个字段中:value 和 data。交易可以同时有 value
    和data,也可以仅有value、仅有data,也可以value、data都没有。
  • 仅有value的交易就是一笔以太的付款。
  • 仅有data的交易一般是合约调用。
  • 进行合约调用的同时,除了传输data,还可以发送以太,即交易中同时有 value 和 data。
  • 没有value也没有data的交易只是在浪费gas,但是它是有效的。
  • 给他人转账的同时还可发送data

向EOA或合约传递data

  • 当交易包含数据有效负载时,它很可能是发送到合约地址的,但它同样可以发送给EOA。
  • 如果发送data给EOA,数据负载(data payload)的解释取决于钱包。
  • 如果发送数据负载给合约地址,EVM会解释为函数调用,从payload里解码出函数名称和参数,调用该函数并传入参数。
  • 发送给合约的数据有效负载是32字节的十六进制序列化编码:(0x(4个字节头)+00000+参数(尾))
    • 函数选择器:函数原型的 Keccak256 哈希的前4个字节。这允许EVM明确地识别将要调用的函数(将函数原型进行哈希取前四个字节)
    • 函数参数:根据EVM定义的各种基本类型的规则进行编码

特殊交易(创建部署合约)

  • 有一种特殊的交易,具有数据负载且没有value,那就是一个创建新合约的交易。
  • 合约创建交易被发送到特殊目的地地址,即零地址0x0。该地址既不代表EOA也不代表合约。它永远不会花费以太或发起交易,它仅用作目的地,具有特殊含义“创建合约”
  • 虽然零地址仅用于合同注册,但它有时会收到来自各种地址的付款。这种情况要么是偶然误操作,导致失去以太:要么是故意销毁以太。
  • 合约注册交易不应包含以太值,只包含合约的已编译字节码的数据有效负载。此交易的唯一效果是注册合约。
  • 24
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python以太坊交易是指使用Python编程语言进行以太坊区块链上的交易操作。以太坊是一种基于区块链技术的智能合约平台,它允许开发者构建和部署去中心化应用程序(DApps)。 在Python中,可以使用以太坊的官方库web3.py来进行以太坊交易的编程操作。web3.py提供了一系列的API,可以与以太坊节点进行通信,并执行各种操作,包括创建账户、发送交易、查询余额等。 以下是一个简单的Python代码示例,展示了如何使用web3.py库发送以太坊交易: ```python from web3 import Web3 # 连接到以太坊节点 w3 = Web3(Web3.HTTPProvider('https://mainnet.infura.io/v3/your_infura_project_id')) # 设置发送方账户私钥和接收方地址 private_key = 'your_private_key' receiver_address = '0x1234567890abcdef1234567890abcdef12345678' # 构建交易参数 transaction = { 'to': receiver_address, 'value': w3.toWei(1, 'ether'), 'gas': 21000, 'gasPrice': w3.toWei('50', 'gwei'), 'nonce': w3.eth.getTransactionCount(w3.eth.accounts), } # 签名交易 signed_transaction = w3.eth.account.signTransaction(transaction, private_key) # 发送交易 transaction_hash = w3.eth.sendRawTransaction(signed_transaction.rawTransaction) # 等待交易确认 transaction_receipt = w3.eth.waitForTransactionReceipt(transaction_hash) # 打印交易结果 print('交易成功,交易哈希:', transaction_receipt.transactionHash.hex()) ``` 上述代码中,首先使用`Web3`类连接到以太坊节点。然后设置发送方账户的私钥和接收方地址。接下来,构建交易参数,包括接收方地址、转账金额、燃气限制、燃气价格和交易序号。然后使用发送方账户的私钥对交易进行签名,并发送签名后的交易以太坊网络。最后,等待交易被确认,并打印交易结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值