algorand / algorand-sdk-testing

Testing framework for Algorand SDKs
MIT License
20 stars 35 forks source link

Support simulating unsigned transactions in the SDK #267

Closed algochoi closed 1 year ago

algochoi commented 1 year ago

Problem: Supporting unsigned transaction simulation in SDKs

Currently, our SDKs generally do not support sending unsigned transactions to algod, due to encoding schemes (encoding into msgpack without signatures may throw an error).

For instance in the JavaScript SDK, before sending or simulating a transaction, we need to encode the transaction into msgpack before calling the endpoint. However, this is explicitly disallowed in our encoding functions (example here). This has the advantage of ensuring that people are sending signed transactions, but we do not need to enforce this for simulations.

For the simulate endpoint in the SDKs, we should support for simulating unsigned transactions so users can see what to expect from a transaction before they commit to signing it. We would need to support this both generally (sending "raw" group transactions through the simulate REST endpoint in the respective SDKs) and in the Atomic Transaction Composer.

Encoding and Decoding transaction objects without signatures

The SDKs have checks that throw an exception if a transaction is not signed and attempted to be sent to an algod. For the JS SDK, this is done when encoding the transaction to msgpack. We will need to introduce a new encoding method to allow unsigned txns be encoded propery to msgpack and sent to the simulate endpoint.

The simplest way is to create a SignedTransaction object (or equivalent) and pass in null for the signature (sig) field. If there are any null or zero checks in the encoding functions of the SDK, we will need to disable that for unsigned transactions.

We also have to allow decoding unsigned transactions in the composer here.

Atomic Transaction Composer

If a user wants to simulate a group with the ATC, the group should at least be BUILT. Without building, the simulation will fail anyway because the groupID will not be present for the transactions. The composer also has no reason to simulate submitted transactions since they will error as duplicate transactions, so the group should be lower than SUBMITTED. The simulate method should be able to simulate signed or unsigned transactions.

In addition, we will have to support an additional transactional signer factory method (e.g. makeDummyTransactionalSigner()) that will accept no actual signers and encode the unsigned transaction as-is. This also has to be in msgpack format that can be decoded by algod.

e.g.

/**
 * Create a makeDummyTransactionSigner that does not specify any signer or
 * signing capabilities. This should only be used to simulate transactions.
 */
export function makeDummyTransactionSigner(): TransactionSigner {
  return (_txnGroup: Transaction[], _indexesToSign: number[]) => {
    const unsigned: Uint8Array[] = [];

    for (const txn of _txnGroup) {
      unsigned.push(encodeUnsignedTransaction(txn));
    }

    return Promise.resolve(unsigned);
  };
}

Testing

We will need to add some SDK tests in cucumber for simulating unsigned transactions and empty signers in the composer.

algochoi commented 1 year ago

update: Currently we support the simulate endpoint for goal, py-algorand-sdk, and js-algorand-sdk

jasonpaulos commented 1 year ago

It seems like most of the concerns here have been addressed, at least in the JS SDK. For example:

Are there any unresolved issues that I missed, or this is good to close?