mirror of
				https://github.com/ChristopherA/Learning-Bitcoin-from-the-Command-Line.git
				synced 2025-11-04 12:28:15 +00:00 
			
		
		
		
	Update 12_3_Programming_Bitcoind_with_C.md
This commit is contained in:
		
							parent
							
								
									2dc8591e7d
								
							
						
					
					
						commit
						2e525a19bd
					
				@ -324,3 +324,340 @@ The entire code, with a _little_ more error-checking appears in the Appendix.
 | 
				
			|||||||
## Summary: Programming Bitcoind with C
 | 
					## Summary: Programming Bitcoind with C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Using the techniques outlined in [§12.2](12_2_Accessing_Bitcoind_with_C.md) you can write a much more complex program using C calls. This section offers an example, with the first cut of a program that will send money to an address, without your users worrying about where it's coming from, how much they're paying as a fee, or how they get their change back. Obviously, a real-world program would need much better user-input control and error handling, but by outlining how the RPC code works, this section opens up the programming doorways to allow you to take the next step.
 | 
					Using the techniques outlined in [§12.2](12_2_Accessing_Bitcoind_with_C.md) you can write a much more complex program using C calls. This section offers an example, with the first cut of a program that will send money to an address, without your users worrying about where it's coming from, how much they're paying as a fee, or how they get their change back. Obviously, a real-world program would need much better user-input control and error handling, but by outlining how the RPC code works, this section opens up the programming doorways to allow you to take the next step.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Appendix: Sending to an Address
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Here's the complete code for sending funds to someone using C.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WARNING: This code has not been robustly checked. Beyond that, it's to be functionally minimalistic, not containing necessary error-checking. If you use it as a foundation of your own work, be sure to check it carefully and to make it a lot more robust.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					file: sendtoaddress.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <jansson.h>
 | 
				
			||||||
 | 
					#include <bitcoinrpc.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* 1. Request an Address and an Amount */
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  if (argc != 3) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    printf("ERROR: Only %i arguments! Correct usage is '%s [recipient] [amount]'\n",argc-1,argv[0]);
 | 
				
			||||||
 | 
					    exit(-1);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  char *tx_recipient = argv[1];
 | 
				
			||||||
 | 
					  double tx_amount = atof(argv[2]);
 | 
				
			||||||
 | 
							   
 | 
				
			||||||
 | 
					  /* 2. Set an Arbitrary Fee */
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  double tx_fee = 0.0005;
 | 
				
			||||||
 | 
					  double tx_total = tx_amount + tx_fee;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* X. Prepare Your RPC */
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  bitcoinrpc_cl_t *rpc_client;
 | 
				
			||||||
 | 
					  bitcoinrpc_method_t *rpc_method  = NULL;
 | 
				
			||||||
 | 
					  bitcoinrpc_resp_t *btcresponse  = NULL;
 | 
				
			||||||
 | 
					  bitcoinrpc_err_t btcerror;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  json_t *lu_response = NULL;
 | 
				
			||||||
 | 
					  json_t *lu_result = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bitcoinrpc_global_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  rpc_client = bitcoinrpc_cl_init_params ("bitcoinrpc", "73bd45ba60ab8f9ff9846b6404769487", "127.0.0.1", 18332);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (rpc_client) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* 3. Find a UTXO */
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    rpc_method = bitcoinrpc_method_init(BITCOINRPC_METHOD_LISTUNSPENT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!rpc_method) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      printf("ERROR: Unable to initialize listunspent method!\n");
 | 
				
			||||||
 | 
					      exit(-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    btcresponse = bitcoinrpc_resp_init();
 | 
				
			||||||
 | 
					    if (!btcresponse) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      printf("Error: Cannot initialize response object!");
 | 
				
			||||||
 | 
					      exit(-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    bitcoinrpc_call(rpc_client, rpc_method, btcresponse, &btcerror);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (btcerror.code != BITCOINRPCE_OK) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      printf("Error: listunspent error code %d [%s]\n", btcerror.code,btcerror.msg);
 | 
				
			||||||
 | 
					      exit(-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lu_response = bitcoinrpc_resp_get (btcresponse);
 | 
				
			||||||
 | 
					    lu_result = json_object_get(lu_response,"result");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *tx_id = 0;
 | 
				
			||||||
 | 
					    int tx_vout = 0;
 | 
				
			||||||
 | 
					    double tx_value = 0.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0 ; i < json_array_size(lu_result) ; i++) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      json_t *lu_data = NULL;
 | 
				
			||||||
 | 
					      lu_data = json_array_get(lu_result, i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      json_t *lu_value = NULL;
 | 
				
			||||||
 | 
					      lu_value = json_object_get(lu_data,"amount");
 | 
				
			||||||
 | 
					      tx_value = json_real_value(lu_value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (tx_value > tx_total) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        json_t *lu_txid = NULL;
 | 
				
			||||||
 | 
						      lu_txid = json_object_get(lu_data,"txid");
 | 
				
			||||||
 | 
					        tx_id = strdup(json_string_value(lu_txid));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        json_t *lu_vout = NULL;
 | 
				
			||||||
 | 
						      lu_vout = json_object_get(lu_data,"vout");
 | 
				
			||||||
 | 
					        tx_vout = json_integer_value(lu_vout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        json_decref(lu_value);
 | 
				
			||||||
 | 
						      json_decref(lu_txid);
 | 
				
			||||||
 | 
						      json_decref(lu_vout);
 | 
				
			||||||
 | 
						      json_decref(lu_data);
 | 
				
			||||||
 | 
						      break;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    json_decref(lu_result);
 | 
				
			||||||
 | 
					    json_decref(lu_response);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
					    if (!tx_id) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      printf("Very Sad: You don't have any UTXOs larger than %f",tx_total);
 | 
				
			||||||
 | 
					      exit(-1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bitcoinrpc_method_free(rpc_method);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /* 4. Create a Change Address */
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    rpc_method = bitcoinrpc_method_init(BITCOINRPC_METHOD_GETRAWCHANGEADDRESS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!rpc_method) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      printf("ERROR: Unable to initialize createrawchangeaddress method!\n");
 | 
				
			||||||
 | 
					      exit(-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bitcoinrpc_call(rpc_client, rpc_method, btcresponse, &btcerror);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (btcerror.code != BITCOINRPCE_OK) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      printf("Error: createrawchangeaddress error code %d [%s]\n", btcerror.code, btcerror.msg);
 | 
				
			||||||
 | 
					      exit(-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lu_response = bitcoinrpc_resp_get (btcresponse);
 | 
				
			||||||
 | 
					    lu_result = json_object_get(lu_response,"result");
 | 
				
			||||||
 | 
					    char *changeaddress = strdup(json_string_value(lu_result));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    json_decref(lu_result);
 | 
				
			||||||
 | 
					    json_decref(lu_response);
 | 
				
			||||||
 | 
					    bitcoinrpc_method_free(rpc_method);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /* 5. Create a Raw Transaction */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* 5.1. Create the Input Parameters */
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    json_t *inputtxid = NULL;
 | 
				
			||||||
 | 
					    inputtxid = json_object();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    json_object_set_new(inputtxid,"txid",json_string(tx_id));
 | 
				
			||||||
 | 
					    json_object_set_new(inputtxid,"vout",json_integer(tx_vout));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    json_t *inputparams = NULL;
 | 
				
			||||||
 | 
					    inputparams = json_array();
 | 
				
			||||||
 | 
					    json_array_append(inputparams,inputtxid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* 5.2 Create the Output Parameters */
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    json_t *outputparams = NULL;
 | 
				
			||||||
 | 
					    outputparams = json_object();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    char tx_amount_string[32];
 | 
				
			||||||
 | 
					    sprintf(tx_amount_string,"%.8f",tx_amount);
 | 
				
			||||||
 | 
					    char tx_change_string[32];
 | 
				
			||||||
 | 
					    sprintf(tx_change_string,"%.8f",tx_value - tx_total);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    json_object_set(outputparams,
 | 
				
			||||||
 | 
								tx_recipient,
 | 
				
			||||||
 | 
								json_string(tx_amount_string));
 | 
				
			||||||
 | 
					    json_object_set(outputparams,
 | 
				
			||||||
 | 
								changeaddress,
 | 
				
			||||||
 | 
								json_string(tx_change_string));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* 5.3 Create the Parameter Array */
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    json_t *params = NULL;
 | 
				
			||||||
 | 
					    params = json_array();
 | 
				
			||||||
 | 
					    json_array_append(params,inputparams);
 | 
				
			||||||
 | 
					    json_array_append(params,outputparams);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* 5.4 Make the RPC Call */
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    rpc_method = bitcoinrpc_method_init(BITCOINRPC_METHOD_CREATERAWTRANSACTION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!rpc_method) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      printf("ERROR: Unable to initialize createrawtransaction method!\n");
 | 
				
			||||||
 | 
					      exit(-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (bitcoinrpc_method_set_params(rpc_method, params) != BITCOINRPCE_OK) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      fprintf (stderr, "Error: Could not set params for createrawtransaction");
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    json_decref(inputtxid);
 | 
				
			||||||
 | 
					    json_decref(inputparams);
 | 
				
			||||||
 | 
					    json_decref(outputparams);
 | 
				
			||||||
 | 
					    json_decref(params);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
					    bitcoinrpc_call(rpc_client, rpc_method, btcresponse, &btcerror);    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (btcerror.code != BITCOINRPCE_OK) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      printf("Error: createrawtransaction error code %d [%s]\n", btcerror.code,btcerror.msg);
 | 
				
			||||||
 | 
					      exit(-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lu_response = bitcoinrpc_resp_get(btcresponse);
 | 
				
			||||||
 | 
					    lu_result = json_object_get(lu_response,"result");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *tx_rawhex = strdup(json_string_value(lu_result));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    json_decref(lu_result);
 | 
				
			||||||
 | 
					    json_decref(lu_response);
 | 
				
			||||||
 | 
					    bitcoinrpc_method_free(rpc_method);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* 6. Sign the Transaction */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    params = json_array();
 | 
				
			||||||
 | 
					    json_array_append_new(params,json_string(tx_rawhex));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rpc_method = bitcoinrpc_method_init(BITCOINRPC_METHOD_SIGNRAWTRANSACTION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!rpc_method) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      printf("ERROR: Unable to initialize signrawtransaction method!\n");
 | 
				
			||||||
 | 
					      exit(-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (bitcoinrpc_method_set_params(rpc_method, params) != BITCOINRPCE_OK) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      fprintf (stderr, "Error: Could not set params for signrawtransaction");
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    json_decref(params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bitcoinrpc_call(rpc_client, rpc_method, btcresponse, &btcerror);    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (btcerror.code != BITCOINRPCE_OK) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      printf("Error: signrawtransaction error code %d [%s]\n", btcerror.code,btcerror.msg);
 | 
				
			||||||
 | 
					      exit(-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lu_response = bitcoinrpc_resp_get(btcresponse);
 | 
				
			||||||
 | 
					    lu_result = json_object_get(lu_response,"result");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    json_t *lu_signature = json_object_get(lu_result,"hex");
 | 
				
			||||||
 | 
					    char *tx_signrawhex = strdup(json_string_value(lu_signature));
 | 
				
			||||||
 | 
					    json_decref(lu_signature);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    json_decref(lu_result);
 | 
				
			||||||
 | 
					    json_decref(lu_response);
 | 
				
			||||||
 | 
					    bitcoinrpc_method_free(rpc_method);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* 7. Sign the Transaction */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    params = json_array();
 | 
				
			||||||
 | 
					    json_array_append_new(params,json_string(tx_signrawhex));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rpc_method = bitcoinrpc_method_init(BITCOINRPC_METHOD_SENDRAWTRANSACTION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!rpc_method) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      printf("ERROR: Unable to initialize sendrawtransaction method!\n");
 | 
				
			||||||
 | 
					      exit(-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (bitcoinrpc_method_set_params(rpc_method, params) != BITCOINRPCE_OK) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      fprintf (stderr, "Error: Could not set params for sendrawtransaction");
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    json_decref(params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bitcoinrpc_call(rpc_client, rpc_method, btcresponse, &btcerror);    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (btcerror.code != BITCOINRPCE_OK) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      printf("Error: endrawtransaction error code %d [%s]\n", btcerror.code,btcerror.msg);
 | 
				
			||||||
 | 
					      exit(-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lu_response = bitcoinrpc_resp_get(btcresponse);
 | 
				
			||||||
 | 
					    lu_result = json_object_get(lu_response,"result");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *tx_newid = strdup(json_string_value(lu_result));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    printf("Txid: %s\n",tx_newid);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    json_decref(lu_result);
 | 
				
			||||||
 | 
					    json_decref(lu_response);
 | 
				
			||||||
 | 
					    bitcoinrpc_method_free(rpc_method);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    printf("ERROR: Failed to connect to server!\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bitcoinrpc_cl_free(rpc_client);
 | 
				
			||||||
 | 
					  bitcoinrpc_global_cleanup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					Compile this as usual:
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					$ cc sendtoaddress.c -lbitcoinrpc -ljansson -o sendtoaddress
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					You can then use it to send funds to an address:
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					$ ./sendtoaddress mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf .10
 | 
				
			||||||
 | 
					Txid: 23f3faea4e1e933e981fe7ed66008f33c00983a865f6ccce9af0005e9670e916
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					You can see information on this transaction that we sent [here](https://live.blockcypher.com/btc-testnet/tx/23f3faea4e1e933e981fe7ed66008f33c00983a865f6ccce9af0005e9670e916/). 
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user