Transaction creation protocol - hadescoincom/hds-core GitHub Wiki

Transaction creation protocol

Creating transactions in Hds (as with other MimbleWimble implementations) is interactive. In order to create a new Hds transaction, the sending and receiving wallets communicate with each other. The wallets exchange parameters which produce the transaction. As a result, the protocol between the wallets is extendable.

What is a transaction in Hds?

Any Hds transaction contains the following parameters:

  • A Set of input UTXOs (Inputs), which have to already be present in the blockchain.
  • A Set of newly created UTXOs (Outputs) and rangeproofs for each output
  • The Explicit excess (offset)
  • The transaction kernel

The transaction kernel requires the following parameters:

  • Blinded excess
  • Transaction fee
  • Minimum height
  • Maximum height
  • Signature. This is a Schnorr’s multi-signature which signs all the values listed above

The minimum and maximum height values set the time in which the transaction is valid. Nodes will reject a transaction if its height is below the minimum height and greater than the maximum height

A simple transaction flow.

In the following example, a Sender makes a payment to a Receiver.

  • Sender and Receiver agree on the amount and fee.
  • The Sender selects input UTXO which allow paying amount + fee.
    • If the sum of inputs is greater than amount + fee, Sender also creates output UTXO for the change.
    • The Sender creates overall blinding excess value blindingExcess_S and offset_S
  • The Receiver creates outputs for a given amount and calculates blinding excess blindingExcess_R and offset_R
  • Both parties generate nonces nonce_S and nonce_R respectively.
  • Both parties send each other public forms of excesses:
    • publicNonce_S = nonce_S*G and publicNonce_R = nonce_R*G – public nonces
    • publicExcess_S = blindingExcess_S*G and publicExcess_R = blindingExcess_R*G – public blinding excessed
  • Both parties compute total blinding excess and total public nonce:
    • total blinding excess: X = publicExcess_S + publicExcess_R
    • total public nonce: K = publicNonce_S + publicNonce_R
  • Both parties compute a Schnorr’s signature challenge:
    • e = H(K|M), where M is a signed message, it calculates from kernel and it includes X, fee, min height, and max height
  • Both parties compute and send to each other partial signatures:
    • S: partialSignature_S = publicNonce_S + e*publicExcess_S
    • R: partialSignature_R = publicNonce_R + e*publicExcess_R
  • Final signature is computed: signature = partialSignature_S + partialSignature_R

/images/SimpleTransactionFlow.png

Wallet-To-Wallet protocol

The protocol itself consists of a single message and can be implemented in all the possible scenarios and transaction types. This message can be encapsulated and passed to other parties by different protocols, such as a direct message over a peer-to-peer connection, or an indirect message sent through the Secure Bulletin Board System (SBBS), and others.

SetTxParameter

  • Transfers a bundle of transaction parameters from one wallet to another. This message may initiate a new transaction.
  • WalletID m_From – The response address set by the wallet, used when sending messages over SBBS. WalletID is a packed 8 bytes of the SBBS channel and 32 bytes of the wallet’s public key.
  • TxID m_TxID – Unique 16-byte transaction identifier. Generated by the transaction initiator.
  • TxType m_Type – Transaction type (Simple, AtomicSwap etc.) This field is used to create a new transaction object when this message is the first in the line, or for verification purposes otherwise.
  • std::vector<std::pair<TxParameterID, ByteBuffer>> m_Parameters – Vector of transaction parameter pairs. Each parameter is a pair of IDs from the range [0...255] and the value represented as a raw bytes buffer. ID values are separated in two parts: private and public (IDs below PrivateFirstParam == 128 are private). Public parameters come from outside and they are not allowed to be overridden. Private parameters do not have limitations.

Example: Simple transaction

A simple transaction is a payment from Wallet A to Wallet B, with a change UTXO and a fee.

Wallet A sends an invitation.

SetTxParameter
{
    m_From: XXXXXX // response address set by wallet A. 
    m_TxID: 651798 //newly generated random identifier.
    m_Type: TxType::Simple,
    [
        {TxParameterID::Amount, amount},
        {TxParameterID::Fee, fee},
        {TxParameterID::MinHeight, minHeight}, 
        {TxParameterID::MaxHeight, maxHeight}, 
        {TxParameterID::IsSender, false}, // flag to distinguish the sender from the receiver 
        {TxParameterID::PeerProtoVersion, protocolVersion}, // current version is 1
        {TxParameterID::PeerPublicExcess, publicExcess}, 
        {TxParameterID::PeerPublicNonce, publicNonce}
    ]
}
  • minHeight - if the height of the blockchain is less than the specified value, the transaction will not be taken into account
  • maxHeight - if the height of the blockchain is greater than the specified then the node will reject the created transaction.
  • protocolVersion - version of wallet-to-wallet protocol
  • publicExcess - the public form of the sender’s excess calculated from blinding factors of inputs and change output.
  • publicNonce - sender generates a secret nonce, this is its public value.

Wallet B confirms invitation.

Wallet B creates an output for the received amount and generates a nonce to sign the transaction.

SetTxParameter
{
    m_From: YYYYYY  // response address set by wallet B.  
    m_TxID: 651798, // the ID set by the  sender.
    m_Type: TxType::Simple,
    [
        {TxParameterID::PeerProtoVersion, protocolVersion}
        {TxParameterID::PeerPublicExcess, peerPublicExcess},
        {TxParameterID::PeerSignature, receiversPartialSignature},
        {TxParameterID::PeerPublicNonce, publicNonce},
        {TxParameterID::PeerOutputs, outputs},
        {TxParameterID::PeerOffset, offset}
    ]
}
  • protocolVersion - version of wallet-to-wallet protocol
  • peerPublicExcess - receiver’s public excess, calculated from the output’s blinding factors.
  • receiversPartialSignature - receiver’s part of Schnorr multi-signature.
  • publicNonce - the public form of a nonce for signature.
  • outputs - vector of outputs, created by the receiver.
  • offset - offset value, randomly taken part of outputs blinding factor.

Wallet A confirms the transaction.

If the receiver’s signature is valid, sender calculates its part of the signature. Now Wallet A has all required data to create the transaction and broadcast it to a node.

Cancellation or error

If any of the participants wish to interrupt the process, they broadcast the following message:

SetTxParameter 
{
    m_From: ZZZZZZ // response address set by the wallet
    m_TxID: 651798, // the ID set by the sender.    m_Type: TxType::Simple,
    [
        {TxParameterID::FailureReason, reason}
    ]
}
  • reason - 32 bit code of failure reason

Note: Cancellation is possible only in specific moments of this flow. Receiver can cancel transaction only during invitation, i.e. after receiver has accepted invitation and sent his data to the sender, he has no guaranties that transactions will not be written into the blockchain. Sender can interrupt transaction only before he sent transaction to the node.