Operación inyectada al nodo, pero no agregada a blockchain | Error del contador de billetera
1 respuesta
- votos
-
- 2020-01-02
TLDR : laprimera operación queinyectóen sunodoes válidaperonunca seráinyectadapor otrosnodos/panaderosporquetiene tarifas demasiadobajas. Luego sebloqueaen elmempool y hace que laspróximas operaciones queintente falsificar seaninválidasporqueelpróximo contador válido que desea usar yaestá siendotomadopor la operación detarifa demasiadobaja. Puede reiniciar sunodo oesperar a quepasen 60bloquespara desbloquear la situación.
Lo que creo que sucede aquíes que laprimera operación queinyectóes consideradainválidapor sus otrospares. Como dijiste,sepuede rechazarpor varias razones (el casomás comúnes queno haya suficientestarifas).
Entonces,falsificó una operación quees válida con respecto alprotocolo y,por lotanto,válidaen elmempool. Sunodo aceptóinyectar la operaciónporque algunospanaderospodríanestar aceptandoe incluyendo 0 operaciones detarifas. Sinembargo,deformapredeterminada,estenoesel caso. La operación queinyectasteen elnodoes vivir asíen elmempoolesperando a que unpanadero loincluyaen unbloque.
Ahora viene lapartetécnica. Cuando solicitas alnodo queforje una operaciónporti,el cliente (o la API queestás usando) solicitará alnodoel contador asociado atu cuenta (nota almargen:el contadorestá aquíparaevitar ataques de repetición). Para obtenerestainformación,elnodo consultará los datos utilizandoel estado actual de la cadena (es decir,elestado que resulta de la aplicación del últimobloque recibido) y devolverá,porejemplo,
1000
. Para que la operación queestáfalsificando sea válida,su contador debe ser1001
. Siestenoesel caso,le dará unerror decontadoren elpasado
ocontadoren elfuturo
cuandoelnodointente validarlo.En su caso,inyectó una operación de tarifa demasiadobaja con un contador
128324
. Sunodo considera que sabe lo queestá haciendo (porejemplo,tratando de que unpanadero debajo costo loinyecte) y,por lotanto,no verifica lastarifas. Sino hayningúnpanadero debajo costofuncionandoen la red,su operaciónnunca seincluirá y sebloquearáen elmempoolpor60
bloques (20minutos comomínimoen babylonnet). Después deesos 60bloques,la operación se considerará demasiado antigua y sepurgará delmempool. Esporeso que,después de algunosmomentos,la situación se desbloqueó.Ahora,mientrasesta operacióninválidaestá atascadaen elmempool,lapróxima operación quefalsifique usandoel clientetambién solicitaráel contador delnodo y como su última operaciónnofueincluida,el contador anterior
128324
se utilizará denuevo,lo que choca con latransacción anterior. Cuandoesto sucede,elmempoolnoestá contentoporqueintentará validar las operaciones unatras otra. Como suprimera operaciónes válida (incluso sinunca seincluirá),se aplicaráen suestadointerno ,quees unestadointermedio donde se aplicó suprimera operación,por lo queel siguiente contadoresperado aumentaráen uno. Lapróxima vez que se reciba una operación (para lamisma cuenta),elmempoolesperará queel contador aumente a128325
. Siesenoesel caso,lo rechazará con unerrorcontadoren elpasado
. Siintenta aumentarmanualmenteel contador,esposible que obtengacontadoren elfuturo
.Cómo salir deesta situación:
- puedeesperar a quepasen 60bloques y luego sutransacción se descartarápor ser demasiado antigua;
- puede reiniciar sunodo sitiene control sobre él. Elmempool seborra cuandoelnodo se detiene;
- puedefalsificare inyectar sutransacción utilizando otronodo. Uno,quenotendrá la operacióninválida atascadaen sumempool.
En lapróxima versión de shell,nuestro objetivoesincluir una RPC de administrador que se utilizaráparaeliminar una operaciónespecífica delmempool.
P.S. Puede verificar qué operaciones vivenen elmempool usandoel RPC
/chains/main/mempool/extended_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
-
¿Cómoenviaríaentonces variastransaccionesen elmismobloque?¿No significaeso quemientras la operación anterior aúnnoesté confirmada,nopodemostransmitirninguna operaciónnueva debido aesta discrepancia allí?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
Utilizomi propionodo debabbylon ypreviamente agregué unabilletera detezosfaucet yenvié algunasmonedas ami billeteragenerada contezos-client:
Enviarmedianteeztz.js
Ahoraestoytratando deenviartezos de unabilleteragenerada a otra coneztz.js lib. Utiliceeste código:
Cuando loejecutoporprimera vez,elnodoinyectami operacióne incluso la dirección de retorno de latransacción,peroestatransferenciano se agregó ablockchain,mi saldono cambió. Registros de operacionesporprimera vez:
Cuando seintentóenviarpor segunda vez,apareceelerror del contador:
Registros de la segunda vez:
Si configuramanualmenteel contadoren 128326,recibiráelerror
counter_in_the_future
.Elerror del contador desapareció después demedia hora,pero aún así,siintentoenviarmonedas,la operaciónno seincluiráen blockchain y recibiréelerror del contadornuevamente.
Enviarmediantetezos-client
Importémi claveprivadagenerada comotest_w2e intentoenviarmonedas contezos-client:
Laprimera vez que obtengoelmismoerror de contador:
Pero después demedia horafuncionó:
Eso significa,errornoen lageneración debilleteras onodo detezos,elerrorpuede ser soloen el clienteeztz.js o valorespasados ¿Quizáspasé latarifa/límite degas/montoincorrecto?
¿Cómopuedo solucionaresteproblema?
Nota. En realidad,utilizo labiblioteca Tz.Netbifurcada (c #),perotiene elmismoflujo detrabajo queeztz.js y recibo losmismoserrores.