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

Improving validation check for transaction #145

Open
hayarobi opened this issue May 31, 2022 · 3 comments
Open

Improving validation check for transaction #145

hayarobi opened this issue May 31, 2022 · 3 comments

Comments

@hayarobi
Copy link
Member

A digital signature is required for Argo's transactions, but when calling hashTransaction, it calculate without a error, assuming a digital signature is empty. If this transaction with wrong calculated invalid hash is sent to the server, the server returns a TX_INVALID_HASH error because the server calculates the hash value including the signature. I know tt is actually user's fault, but I think it would be better to do more detailed and kind validation at the SDK level. This validation will prevent both the client and the server from unnecessary loads.

And if the transaction without digital signature is sent, UNDEFINED_ERROR: malformed signature: too short error is returned. In this case as well, I think it would be better if the herajs check it before sending it to the server and send it.

@hayarobi
Copy link
Member Author

Here is the sample code i wrote.

import {AergoClient, GrpcProvider} from "@herajs/client";
import {
    createIdentity,
    signTransaction,
    hashTransaction,
    verifyTxSignature,
    encodeTxHash,
    encryptPrivateKey, keystoreFromPrivateKey, identityFromKeystore, encodePrivateKey, decodePrivateKey
} from '@herajs/crypto';
import {base58, encodeBuffer, toHexString} from "@herajs/common";
import {decryptPrivateKey, identityFromPrivateKey} from "@herajs/crypto";

const testnode_url = 'localhost:7845';
// const testnode_url = 'alpha-api.aergo.io:7845';
//const testnode_url = 'testnet-api.aergo.io:7845';
const aergoClient = new AergoClient({},
    new GrpcProvider({url: testnode_url}));

//    Sign and Send Transaction
async function sendTx() {
    let identity;
    if( false ) {
        identity = createIdentity();
        console.log("address", identity.address);
        const keystore = await exportIdentity(identity.privateKey, 'pass');
    } else {
        identity = await importIdentity("488f74x19Xi86Wfe3D2yCyDhdAacpfR8qRFG1jTorJ3fc8XdvphCd7TtqwYKiq7DinxiMqbQz","pass")
    }

    const tx = {
        nonce: 2,
        from: identity.address,
        to: 'AmPJhiRahaVoMAVF9dbPi6qisGzLbs6Hh8N6g7NoLeQ3uYSrb1qL',
        amount: "1300000000000000000 aer",
        payload: "it's payload",
        chainIdHash: await aergoClient.getChainIdHash("base58")
    };
    const signedTx = await signTransaction(tx, identity.keyPair);
    // mistakenly calculated hash before set signature
    const hashBytes = await hashTransaction(tx, "bytes", true);
    const encodedTxHash = encodeBuffer(hashBytes);
    console.log("tx hash in b58",encodedTxHash);
    tx.sign = signedTx; 
    tx.hash = encodedTxHash;

    const verifiedTxSig = await verifyTxSignature(
        tx,
        identity.keyPair,
        signedTx,
    );
    // console.log("verify status",verifiedTxSig);

    const txObj = tx;
    const result = await aergoClient.sendSignedTransaction(txObj);

    console.log("result" , result);
}

async function exportIdentity(privateKey, password) {
    const keystore = await keystoreFromPrivateKey(privateKey, password);
    const wif = encodePrivateKey(await encryptPrivateKey(Uint8Array.from(privateKey), password));

    const strForm = JSON.stringify(keystore, null, 2);
    console.log("keystring",wif)
    return keystore;
}


async function importIdentity(wif, password) {
    const firstPass = decodePrivateKey(wif);
    const secondPass = await decryptPrivateKey(firstPass, password);
    const keystore = await keystoreFromPrivateKey(secondPass, password);
    const identity = await identityFromKeystore(keystore, password)
    return identity;
}

sendTx()

@kroggen
Copy link
Member

kroggen commented May 31, 2022

I use this sequence to send a txn and it works:

  console.log("sending transaction:", tx)

  tx.sign = await crypto.signTransaction(tx, account.keyPair);
  tx.hash = await crypto.hashTransaction(tx, 'bytes');
  const txhash = await aergo.sendSignedTransaction(tx);
  const receipt = await aergo.waitForTransactionReceipt(txhash);

  console.log("transaction receipt:", receipt)

@hayarobi
Copy link
Member Author

hayarobi commented Jun 10, 2022

@kroggen
Yeah, your code is right.
What I want to say is it's better to show clearer error message and stack trace about this human error. One of my clients did the mistake, and was hard to find out where he made mistake since the error message was INVALID_TX_HASH while sending transaction, not while generating txHash.

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

No branches or pull requests

2 participants