Wednesday, 5 July 2017

Bitcoin core tutorial & code walk through (Part 2) - sendtoaddress

1) The bitcoin-cli command can be used to send bitcoin to any recipient address. For testing purpose, the regtest network is used.

bitcoin-cli -regtest getaccountaddress ""  - get the address from default account
bitcoin-cli -regtest sendtoaddress mjSTBVs....... {amount} <comment>  - this returns transaction id

2) In this analysis, the source code that handles sendtoaddress RPC will be walked through.

httprpc.cpp 
In HTTPReq_JSONRPC(HTTPRequest *req, const std::string &)
call jreq.parse(valRequest)    - parse the request
call tableRPC.execute(jreq)  - execute the RPC comamnd

rpc/server.cpp

In CRPCTable::execute(const JSONRPCRequest &request)
initialise pcmd
  CRPCCommand *pcmd = tableRPC[request.strMethod]
The tableRPC array is filled in init.cpp

init.cpp

In AppInitParameterInteraction()
call RegisterAllCoreRPCCommands(tableRPC)
and RegisterWalletRPCCommands(tableRPC)

rpc/register.h

define the function RegisterAllCoreRPCCommands(CRPCTable &t), which calls
RegisterBlockchainRPCCommands(t)
RegisterMiscRPCCommands(t)
RegisterMiningRPCCommands(t)
RegisterRawTransactionRPCCommands(t)

rpc/blockchain.cpp

define RegisterBlockchainRPCCommands(CRPCTable &t)

rpc/net.cpp

define RegisterNetRPCCommands(CRPCTable &t)

rpc/mining.cpp

define RegisterMiningRPCCommands(CRPCTable &t)

rpc/rawtransaction.cpp

define RegisterRawTransactionRPCCommands(CRPCTable &t)

Last but not least, RegisterWalletRPCCommands is defined in

wallet/rpcwallet.cpp

The RegisterWalletRPCCommands(CRPCTable &t) fill up the CRPCCommand array. In the CRPCComamnd structure,  actor function pointer, sendtoaddress function is assigned to that field.

The function
UniValue sendtoaddress(const JSONRPCRequest & request)
Firstly, the address is gotten from parameter 0. Then, the amount is gotten from parameter 1. The it calls the SendMoney() function, and returns the hash value of the transaction.

The function
static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount value, bool fSubtractFeeFromAmount, CWalletTx & wtxNew)
Firstly, it gets the balance from the wallet, parse the bitcoin address, find out the recipient.
Then, it declares std::vector<CRecipient> vecSend
and append the recipient to the array vecSend
Then, it calls CWallet function CreateTransaction and CommitTransaction.

wallet/wallet.cpp
In the CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign)

Firstly, it checks the recipient amount , which must be >= 0. Then, it sets the lockTime to the next block to discourage fee sniping. The CTxOut txout object is constructed. The txout is appended to CMutableTransaction txNew vout vector. Then, it chooses the Bitcoin to use for transaction. If input value is greater than selected value, it creates a CTxOut and insert it to same CMutableTransaction vout at position nChangePosInOut.

After that, it creates CTxIn and appends the CTxIn to vin vector. It calculate the minimum fee needed. If the fee needed is less than min relay fee, the transaction is dropped. Then the min fee inclusive of necessary fee is calculated.

If transaction requires signature, a signature is produced (via ProduceSignature function). UpdateTransaction() is called to update with signature data.

Then, the CMutableTransaction txNew is embedded in CWalletTx wtxNew object. If wtxNew size is bigger than mempool's chain limit, transaction will be dropped.

In the bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state)

It calls AddToWallet(wtxNew) and coin.BindWallet(this) to notify old coins are spent.
It then broadcast transaction if wtxNew is accepted to mempool

bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)

It creates the walletdb. It creates the std:pair object from mapWallet.insert(std::make_pair(hash, wtxIn)). From the std::pair object, it creates another CWalletTx wtx object. If it is new transaction, it gets the order position from walletdb, and adds the hash. If it is not new, the code merges the hash block. Finally, it writes to disk with walletdb.WriteTx(wtx).

mapWallet is declared in wallet/wallet.h as
std::map<uint256, CWalletTx> mapWallet;

2 comments: