Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible bug on signing a TokenBurnV1 transaction #144

Closed
Alex99y opened this issue Feb 18, 2021 · 0 comments · Fixed by #192
Closed

Possible bug on signing a TokenBurnV1 transaction #144

Alex99y opened this issue Feb 18, 2021 · 0 comments · Fixed by #192

Comments

@Alex99y
Copy link

Alex99y commented Feb 18, 2021

Description
The bug happens on signing TokenBurnV1 transactions with an empty memo field, possibly during the encoding transaction process.

Platform
NodeJS 12.16.1
Ubuntu 16.04

Packages versions
@helium/crypto: 3.7.0
@helium/http: 3.22.0
@helium/proto: 1.2.0
@helium/transactions: 3.20.0

Test code

const crypto = require("@helium/crypto")
const http = require("@helium/http")
const { TokenBurnV1, Transaction } = require("@helium/transactions")

async function test() {
    const client = new http.Client();

    const vars = await client.vars.get()
    
    Transaction.config(vars)

    const account1 = await crypto.Keypair.fromWords([ /* hidden */])

    const account = await client.accounts.get(account1.address.b58)

    const txn = new TokenBurnV1({
        payer: account1.address,
        payee: account1.address,
        amount: 5000000,
        nonce: account.speculativeNonce ? account.speculativeNonce + 1 : 1,
        memo: "AAAAAAAAAAA=" // It is equals than an empty string 
    });

    const signedTx = await txn.sign({ payer: account1 }); // <-- The bug happens here

    const pendingTx = await client.transactions.submit(signedTx.toString());
    
    console.log(pendingTx.hash);
}

test().catch(console.log)

Using txn.toString(), it generates the next transaction:

igGWAQohAdV4yDJv/K1vfRCF3rYv+BdC/mvTKICco0/Rl6vzJWfMEiEB1XjIMm/8rW99EIXeti/4F0L+a9MogJyjT9GXq/MlZ8wYwJaxAiCQASpA6nFBqDFxGfDDlGgCmgJYe4e5O/iaHGP0qmzK7/TRQb4JiJECSCxol0fLMAwVL5gddtv3pL8ylxBQiKb3oXQ+DzC4kQI4AA==

Submitting the transaction to the network, fails and gives an invalid signature error. (Failed transaction link)

But, changing the memo field with another value different than an empty string, it works.

const crypto = require("@helium/crypto")
const http = require("@helium/http")
const { TokenBurnV1, Transaction } = require("@helium/transactions")

async function test() {
    const client = new http.Client();

    const vars = await client.vars.get()
    
    Transaction.config(vars)

    const account1 = await crypto.Keypair.fromWords([ /* hidden */ ])

    const account = await client.accounts.get(account1.address.b58)

    const txn = new TokenBurnV1({
        payer: account1.address,
        payee: account1.address,
        amount: 5000000,
        nonce: account.speculativeNonce ? account.speculativeNonce + 1 : 1,
        memo: Buffer.from("Hello World!").toString("base64")
    });

    const signedTx = await txn.sign({ payer: account1 });

    const pendingTx = await client.transactions.submit(signedTx.toString());
    
    console.log(pendingTx.hash);
}

test().catch(console.log)

It generates the next transaction and the node accepted it (Sucessfully transaction link)

igGeAQohAdV4yDJv/K1vfRCF3rYv+BdC/mvTKICco0/Rl6vzJWfMEiEB1XjIMm/8rW99EIXeti/4F0L+a9MogJyjT9GXq/MlZ8wYwJaxAiCQASpAemuJqI/Y8j1Kl3tmkojk5jNb4HnnjM9Z9McTPFzSfeCO/AczudVBYcob0qMiHuTxX6vzXlDKxHE2AZiwlQV7AzC4kQI4yMqx4/aNyKtv

Using the Helium CLI Wallet, it generates and submits perfectly the transaction (Successfully transaction link)

./helium-wallet --format json burn --amount 0.05 --payee 14Zm2aMFGXuHBuCDKLLgWS1wNkWxBndFEAuhyWiCd8KpFJSzQEE
Password: [hidden]
{
"amount": 0.05,
"fee": 35000,
"hash": null,
"memo": "AAAAAAAAAAA=",
"nonce": 144,
"payee": "14Zm2aMFGXuHBuCDKLLgWS1wNkWxBndFEAuhyWiCd8KpFJSzQEE",
"txn": "igGUAQohAdV4yDJv/K1vfRCF3rYv+BdC/mvTKICco0/Rl6vzJWfMEiEB1XjIMm/8rW99EIXeti/4F0L+a9MogJyjT9GXq/MlZ8wYwJaxAiCQASpAGLlwNd+DPM98VW7uL7vRUOrW8Mp6bh6LaJJekgjcJR4WD5Mtv4OcoTvdptpHV5Ujo7rohH8SLiEll1B5aPUABTC4kQI="
}

Extra
Yesterday, a user named Jerm helped me a lot by giving additional information:

Rust:

CiEB1XjIMm/8rW99EIXeti/4F0L+a9MogJyjT9GXq/MlZ8wSIQHVeMgyb/ytb30Qhd62L/gXQv5r0yiAnKNP0Zer8yVnzBjAlrECII8BMLiRAjgA

Field #1: 0A String Length = 33, Hex = 21, UTF8 = "��x�2o��o}��޶/�� ..." (total 31 chars)
Field #2: 12 String Length = 33, Hex = 21, UTF8 = "��x�2o��o}��޶/�� ..." (total 31 chars)
Field #3: 18 Varint Value = 5000000, Hex = C0-96-B1-02
Field #4: 20 Varint Value = 143, Hex = 8F-01
Field #6: 30 Varint Value = 35000, Hex = B8-91-02
Field #7: 38 Varint Value = 0, Hex = 00

HeliumJS:

CiEB1XjIMm/8rW99EIXeti/4F0L+a9MogJyjT9GXq/MlZ8wSIQHVeMgyb/ytb30Qhd62L/gXQv5r0yiAnKNP0Zer8yVnzBjAlrECII8BMLiRAg==

Field #1: 0A String Length = 33, Hex = 21, UTF8 = "��x�2o��o}��޶/�� ..." (total 31 chars)
Field #2: 12 String Length = 33, Hex = 21, UTF8 = "��x�2o��o}��޶/�� ..." (total 31 chars)
Field #3: 18 Varint Value = 5000000, Hex = C0-96-B1-02
Field #4: 20 Varint Value = 143, Hex = 8F-01
Field #6: 30 Varint Value = 35000, Hex = B8-91-02

Jerm's conclusion:

The missing field, #7, is the memo field.
there's a protobuf encoding problem in the signature function.
My hunch is that HeliumJS is unable to properly encode any transaction in which one of the elements is the integer zero. You wouldn't notice this in most transactions, though, because they'd be nonsense.
blockchain_txn_transfer_hotspot_v1 is one that could potentially be visible. If you transfer without requesting HNT payment, it would have an amount_to_seller field of 0.
and it's treating "0" as "empty" instead of null as empty.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant