操作已注入节点,但未添加到区块链钱包计数器错误
1 个回答
- 投票数
-
- 2020-01-02
TLDR :您在节点中注入的第一个操作是有效的,但由于费用太低,因此永远不会被其他节点/面包师注入.然后,它将卡在内存池中,并使您要伪造的下一个操作无效,因为您要使用的下一个有效计数器已经由费用过低的操作占用.您可以重新启动节点,或等待60个区块通过以解除锁定.
我认为这里发生的是您注入的第一个操作被其他同伴认为是无效的.如您所说,可以出于多种原因拒绝付款(最常见的情况是收费不足).
因此,您伪造了关于协议有效的操作,因此在内存池中有效.您的节点已接受注入操作,因为某些面包师可能正在接受并包含0费用操作.但是,默认情况下并非如此.因此,您在节点中注入的操作位于内存池中,等待面包师将其包含在块中.
现在是技术部分.当您请求节点为您伪造一个操作时,客户端(或您正在使用的API)将向该节点请求与您的帐户相关联的计数器(注意:该计数器用于防止重放攻击).为了获取此信息,节点将使用链的当前状态(即,由于接收到的最后一个块的应用而产生的状态)来查询数据,并返回例如
1000
.为了使您进行的伪造操作有效,其计数器必须为1001
.如果不是这种情况,则当节点尝试验证它时,它将为您提供过去的counter
或将来的counter
错误.在您的情况下,您注入了费用太低的操作,并带有计数器
128324
.您的节点认为您知道自己在做什么(例如,尝试让低费用的面包师进行注入),因此不检查费用.如果网络中没有运行费用低廉的面包师,您的操作将永远不会被包含在60
块的内存池中(在babylonnet中最少20分钟).在这60个块之后,该操作将被认为太旧并且已从内存池中清除.这就是为什么一段时间后情况未得到解决的原因.现在,尽管此无效操作被卡在内存池中,但您使用客户端伪造的下一个操作也将向该节点请求计数器,并且由于不包括您的上一个操作,因此上一个计数器
128324
将再次使用,它会与上一个交易发生冲突.发生这种情况时,内存池会感到不满意,因为它将尝试一个接一个地验证操作.由于您的第一个操作是有效的(即使永远不会包括在内),它也会应用于其内部状态,这是您执行了第一个操作的中间状态,从而使下一个预期计数器增加了一.下次(对于同一帐户)接收到一个操作时,内存池将期望计数器增加到128325
.如果不是这种情况,那么它将使用过去的counter
错误拒绝它.如果尝试手动增加计数器,将来可能会获得counter
.如何摆脱这种情况:
- 您可能要等待60个街区经过,然后您的交易会因为过旧而被丢弃;
- 如果您可以控制节点,则可以重新启动它.节点停止时将删除内存池;
- 您可以使用另一个节点进行伪造和注入交易.一种,不会将无效操作卡在其内存池中.
在下一个Shell版本中,我们的目标是包括一个admin RPC,它将用于从内存池中删除特定操作.
P.S.您可以使用RPC
检查内存池中存在哪些操作/chains/main/mempool/pending_operations
TLDR: the first operation you injected in your node is valid but will be never be injected by other nodes/bakers because it has too low fees. It is then stuck in the mempool and make the the next operations you're trying to forge invalid because the next valid counter you want to use is already being taken by the too low fee operation. You can restart your node or wait for 60 blocks to pass to unlock the situation.
What I believe happens here is that the first operation you injected is considered invalid by your other peers. As you said, it can be rejected for multiple reasons (not enough fees being the most common case).
So, you forged an operation which is valid regarding the protocol and therefore valid in the mempool. Your node accepted injecting the operation because some bakers might be accepting and including 0 fees operations. However, by default, this is not the case. The operation you injected in the node is thus living in the mempool waiting for a baker to include it in a block.
So now comes the technical part. When you request the node to forge an operation for you, the client (or the API you're using) will request from the node the counter associated to your account (side note: the counter is here to prevent replay attacks). To grab this information, the node will query the data using the current state of the chain (i.e. the state that results from the application of the last block received) and will return, for example,
1000
. For the operation you're forging to be valid, its counter must then be1001
. If this is not the case, it will give you acounter in the past
orcounter in the future
error when the node is trying to validate it.In your case, you injected a too low fee operation with a counter
128324
. Your node considers that you know what you're doing (e.g. trying to get a low-fee baker to inject it) and thus does not check for the fees. If there are no low-fee baker running in the network, your operation will never be included and stuck in the mempool for60
blocks (20min minimum in babylonnet). After those 60 blocks, the operation will considered too old and purged from the mempool. This is why, after some times, the situation was unlocked.Now, while this invalid operation is stuck in the mempool, the next operation you forge using the client will also request the counter from the node and as your last operation was not included, the previous counter
128324
will be used again which collides with the previous transaction. When this happens, the mempool is not happy because it will try to validate the operations one after the other. As your first operation is valid (even if it will never be included), it will be applied on its internal state which is an intermediate state where your first operation was applied thus making the next expected counter increased by one. The next time an operation is received (for the same account) the mempool will expect the counter to be increased to128325
. If that's not the case, then it will reject it with acounter in the past
error. If you try to manually increase the counter, you might getcounter in the future
.How to get out of this situation:
- you may wait for 60 blocks to pass by and then your transaction will be discarded for being too old;
- you can restart your node if you have control over it. The mempool is erased when the node stops;
- you can forge and inject your transaction using another node. One, which will not have the invalid operation stuck in its mempool.
In the next shell release, we aim to include an admin RPC that will be used to remove a specific operation from the mempool.
P.S. You may check which operations live in the mempool using the RPC
/chains/main/mempool/pending_operations
-
然后,您将如何在同一区块中发送多个交易?这是否意味着只要尚未确认旧操作,就不会因为该不匹配而广播任何新操作?How would you then send multiple transactions in the same block? Doesn't that mean that as long as the old operation is not yet confirmed, we can't broadcast any new operation because of this mismatch there?
- 0
- 2020-05-09
- CherryDT
我使用自己的babbylon节点,以前我从tezos龙头中添加了一些钱包,并使用tezos-client将一些硬币发送到了我生成的钱包中:
通过eztz.js发送
现在,我正尝试使用eztz.js lib将tezos从一个生成的钱包发送到另一个钱包. 使用此代码:
当我第一次执行它时-节点注入了我的操作甚至是交易的返回地址,但是这种转移并没有添加到区块链中,我的余额没有改变.首次操作日志:
第二次尝试发送时-收到计数器错误:
第二时间日志:
如果手动将计数器设置为128326-将收到错误
counter_in_the_future
.半小时后计数器错误消失了,但是如果我尝试发送硬币,仍然不会-区块链将不包含操作,并且我将再次收到计数器错误.
通过tezos-client发送
我将生成的私钥导入为test_w2,并尝试通过tezos-client发送硬币:
我第一次遇到相同的计数器错误:
但是半小时后,它起作用了:
因此,错误不会出现在钱包生成或tezos节点中,错误只能发生在eztz.js客户端或传递的值中.也许我通过了错误的费用/gas_limit/金额?
我该如何解决?
注意.实际上,我使用的是分叉的Tz.Net库(c#),但它的工作流程与eztz.js相同,并且收到相同的错误.