luxtagofficial / Apostille-library

The official Apostille Typescript repository

Home Page:https://apostille.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Separate signing from transaction announcement

dgarcia360 opened this issue · comments

Describe the bug
When creating a public apostille and calling announce() method, it is not possible to fetch the hash of the announced transaction.

This is required to listen if the transaction has been confirmed or not.

this.listener
.confirmed(address)
.pipe( filter((transaction) =>
    transaction.transactionInfo !== undefined
    && transaction.transactionInfo.hash === hash))
.subscribe(transaction => console.log(transaction), err => console.log(err));

To Reproduce
Steps to reproduce the behavior:

apostille.update(message, new SHA256());
from(apostille.announce(nodeUrl) 
.subscribe( _  => // Returns Promise<void>
    { 
        this.notarizationHash = ???; // Can't get transaction hash.
    }, err => console.log(err));

Expected behavior

Decouple signing the transaction from the library.

  • Rename announce() method for createTransaction()
  • createTransaction() returns a Transaction object, which could be Transfer Transaction or aggregate.
  • account.sign(transaction) it is done outside the library.
  • transaction announcement it is done outside the library as well.

It is also a win in security since there is not the need to pass the full account object with the private key to an external library.

Note: It could be more complicated to announce aggregated transactions.

Apostille has a function called `monitor' that can be used to get the transactions as for public apostille we didn't implement that function.

in regards to decoupling the signing and announcement of the transaction from the library, it's actually a sensitive issue because we wanted it to be that way from the beginning and we have a lot of code already dependent on this library.

I personally would prefer to work in solving the problem without doing radical changes.

If you have more suggestions, please let us know.

If I'm not mistaken, this monitors every transaction sent to the account. If I announce the apostille, but someone announces in the middle a transaction to the same account, I would get the incorrect confirmation.

As a first step, a partial solution could be adding transactionHash as a property of PublicApostille. This change shouldn't break anything, and allow to monitor outside the library which is the transaction status.

However, I still think that decoupling the signature form the announcement could be reasonable to evaluate in a 2.0 version for the reasons suggested, as well as being able to monitor transactions before announcing them (avoid missing the notification because it was confirmed before listening).

I believe the extra effort required to separate signing from your library - is time well spent. Consider all the new possibilities for developers using your library! Someone wants to keep the private key at all cost on the Trezor (T) and signs from there? No problem. Another aspect is readability. Separating the signing enables anyone to apply consistently the reactive approach. I would really love to see that.

@dgarcia360 @dexterslabor I really appreciate the feedback will consider the changes when we allocate time for improving the library 😅.

PRs welcomed :)

I believe the extra effort required to separate signing from your library - is time well spent. Consider all the new possibilities for developers using your library! Someone wants to keep the private key at all cost on the Trezor (T) and signs from there? No problem. Another aspect is readability. Separating the signing enables anyone to apply consistently the reactive approach. I would really love to see that.

@dexterslabor Just throwing out some ideas.

Extend Initiator to become more of a driver that can support regular account, multisig accounts and Trezor accounts, other HSMs.

--

@dgarcia360 Regarding the announce function, I am not sure if you can get the transaction hash before you announce. The only way to know if it goes through is to listen to the account or block (correct me if I'm wrong), which the monitor method is currently doing.

Regarding the announce function, I am not sure if you can get the transaction hash before you announce.

You can get the transaction hash when the transaction is signed.

const aliceAccount = Account.createFromPrivateKey('PRIVATE_KEY', NetworkType.MIJIN_TEST);

const transferTransaction = TransferTransaction.create(
        Deadline.create(),
        Account.generateNewAccount(NetworkType.MIJIN_TEST).address,
        [],
        PlainMessage.create('test'),
        NetworkType.MIJIN_TEST);

const signedTransaction = aliceAccount.sign(transferTransaction);
console.log(signedTransaction.hash);

Separating signature from announcement makes the library secure. Imagine you own valuable assets in your account. You will probably not use an external library that asks for your private key (Initiator).

You would prefer to create the apostille transaction with the library, sign it offline, and afterwards announce the transaction to the network.

Hello friends!
Good news. we are trying to rethink the library and we see that the announce function should be isolated
However, it will still be handled by a class in this library (up to the users to use it). and because of that, we are trying to find a better way to take in consideration the HSM signing of transactions.

Since the library right now has a very complicated way of announcing as it takes into consideration all possibilities it needs time and effort to come up with a solid solution. Therefore I invite all of you to contribute to the library (thoughts and code) PRs are welcomed.

With that said after a discussion, we think that we need to upgrade the initiator class to support HSM as @jontey suggested earlier.

Also (correct me if I am wrong) Catapult signing is different from Nis1 which makes it difficult for us to test as there are no Hardware wallets compatible with Catapult as of now.

Below is the changes that we are proposing.

  1. Separate announcement of transactions to ApostilleHttp class. This means that a lot of methods in Apostille class and ApostilleAccount class will be removed.

The resulting class should look like this.

class Apostille {
  # Fields
  public hdAccount: Account;
  
  # Static methods
  # Renamed from init
  static initFromSeed(seed, generatorAccount): Apostille;

  # Public methods
  # This is signed by the Apostille hdAccount as it is the first transaction. 
  associate(owners: PublicAccount[], {deadline, quorum, minRemoval}): SignedTransaction

  # Notes for Apostille class.
  # Methods defined here are those that ONLY require the private key
  # of the hdAccount, any other methods that require signing of a mix
  # of accounts will be placed in ApostillePublicAccount
}
  1. We would follow the naming convention of nem2-sdk to rename ApostilleAccount to ApostillePublicAccount as I believe the key difference between these two classes are with respect to the private key of the apostille account. However, we will refrain from renaming Apostille to ApostilleAccount to prevent any confusion in the future.

Announce methods would now be in ApostilleAccountHttp. The announce method from ApostilleAccount will be moved here as well as any other auxiliary methods.

The Initiator class will be rewritten to support signing from outside sources (type hw). We will add a method to fetch IReadyTransaction that has an Initiator with type hw (hardware wallet). announce method will now check if all transactions have a signer, if not it will return an error.

In summary, we will maintain the current feature set of Apostille-library with some refactor. We will provide ApostilleAccountHttp as a helper method, but you are now free to use any other method to sign or announce Apostille accounts. I would propose that using ApostilleAccountHttp would guarantee that the order of transactions announced would be consistent, as of now, it ensures that the creation message is placed first, before any other transactions (that is why we are keeping it as a separate class). But for those who are willing to manage the order of transactions it is now possible with the caveat that they are now responsible for ensuring consistency of the state of the Apostille on the chain.

Announce methods are now separated from the signing methods.

Documentation has been updated to reflect the changes https://apostille.io/guide/