void btc_tx_serialize(cstring* s, const btc_tx* tx) { ser_s32(s, tx->version); ser_varlen(s, tx->vin ? tx->vin->len : 0); unsigned int i; if (tx->vin) { for (i = 0; i < tx->vin->len; i++) { btc_tx_in* tx_in; tx_in = vector_idx(tx->vin, i); btc_tx_in_serialize(s, tx_in); } } ser_varlen(s, tx->vout ? tx->vout->len : 0); if (tx->vout) { for (i = 0; i < tx->vout->len; i++) { btc_tx_out* tx_out; tx_out = vector_idx(tx->vout, i); btc_tx_out_serialize(s, tx_out); } } ser_u32(s, tx->locktime); }
void btc_tx_copy(btc_tx* dest, const btc_tx* src) { dest->version = src->version; dest->locktime = src->locktime; if (!src->vin) dest->vin = NULL; else { unsigned int i; if (dest->vin) vector_free(dest->vin, true); dest->vin = vector_new(src->vin->len, btc_tx_in_free_cb); for (i = 0; i < src->vin->len; i++) { btc_tx_in *tx_in_old, *tx_in_new; tx_in_old = vector_idx(src->vin, i); tx_in_new = malloc(sizeof(*tx_in_new)); btc_tx_in_copy(tx_in_new, tx_in_old); vector_add(dest->vin, tx_in_new); } } if (!src->vout) dest->vout = NULL; else { unsigned int i; if (dest->vout) vector_free(dest->vout, true); dest->vout = vector_new(src->vout->len, btc_tx_out_free_cb); for (i = 0; i < src->vout->len; i++) { btc_tx_out *tx_out_old, *tx_out_new; tx_out_old = vector_idx(src->vout, i); tx_out_new = malloc(sizeof(*tx_out_new)); btc_tx_out_copy(tx_out_new, tx_out_old); vector_add(dest->vout, tx_out_new); } } }
int btc_node_group_amount_of_connected_nodes(btc_node_group *group) { int cnt=0; for (size_t i = 0; i < group->nodes->len; i++) { btc_node *node = vector_idx(group->nodes, i); if ((node->state & NODE_CONNECTED) == NODE_CONNECTED) cnt++; } return cnt; }
btc_bool btc_tx_is_coinbase(btc_tx* tx) { if (tx->vin->len == 1) { btc_tx_in *vin = vector_idx(tx->vin, 0); if (btc_hash_is_empty(vin->prevout.hash) && vin->prevout.n == UINT32_MAX) return true; } return false; }
btc_bool btc_node_group_connect_next_nodes(btc_node_group *group) { btc_bool connected_at_least_to_one_node = false; int connect_amount = group->desired_amount_connected_nodes - btc_node_group_amount_of_connected_nodes(group); if (connect_amount <= 0) return true; /* search for a potential node that has not errored and is not connected or in connecting state */ for (size_t i = 0; i < group->nodes->len; i++) { btc_node *node = vector_idx(group->nodes, i); if ( !((node->state & NODE_CONNECTED) == NODE_CONNECTED) && !((node->state & NODE_CONNECTING) == NODE_CONNECTING) && !((node->state & NODE_ERRORED) == NODE_ERRORED) ) { /* setup buffer event */ node->event_bev = bufferevent_socket_new(group->event_base, -1, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(node->event_bev, read_cb, write_cb, event_cb, node); bufferevent_enable(node->event_bev, EV_READ|EV_WRITE); if (bufferevent_socket_connect(node->event_bev, (struct sockaddr *)&node->addr, sizeof(node->addr)) < 0) { /* Error starting connection */ if (node->event_bev) bufferevent_free(node->event_bev); return false; } /* setup periodic timer */ node->time_started_con = time(NULL); struct timeval tv; tv.tv_sec = BTC_PERIODICAL_NODE_TIMER_S; tv.tv_usec = 0; node->timer_event = event_new(group->event_base, 0, EV_TIMEOUT|EV_PERSIST, node_periodical_timer, (void*)node); event_add(node->timer_event, &tv); node->state |= NODE_CONNECTING; connected_at_least_to_one_node = true; connect_amount--; if (connect_amount <= 0) return true; } } /* node group misses a node to connect to */ return connected_at_least_to_one_node; }
void test_protocol() { /* get new string buffer */ cstring *version_msg_cstr = cstr_new_sz(256); cstring *inv_msg_cstr = cstr_new_sz(256); struct sockaddr_in test_sa, test_sa_check; memset(&test_sa, 0, sizeof(test_sa)); memset(&test_sa_check, 0, sizeof(test_sa_check)); test_sa.sin_family = AF_INET; struct sockaddr_in6 test_sa6, test_sa6_check; test_sa6.sin6_family = AF_INET6; test_sa6.sin6_port = htons(1024); evutil_inet_pton(AF_INET, "10.0.0.1", &test_sa.sin_addr); // store IP in antelope char i6buf[1024]; memset(&i6buf, 0, 1024); evutil_inet_pton(AF_INET6, "::1", &test_sa6.sin6_addr); btc_p2p_address ipv6Test; btc_p2p_address_init(&ipv6Test); btc_addr_to_p2paddr((struct sockaddr *)&test_sa6, &ipv6Test); btc_p2paddr_to_addr(&ipv6Test, (struct sockaddr *)&test_sa6_check); memset(&i6buf, 0, 1024); u_assert_int_eq(test_sa6.sin6_port, test_sa6_check.sin6_port); /* copy socket_addr to p2p addr */ btc_p2p_address fromAddr; btc_p2p_address_init(&fromAddr); btc_p2p_address toAddr; btc_p2p_address_init(&toAddr); btc_addr_to_p2paddr((struct sockaddr *)&test_sa, &toAddr); btc_p2paddr_to_addr(&toAddr, (struct sockaddr *)&test_sa_check); u_assert_int_eq(test_sa.sin_port, test_sa_check.sin_port); evutil_inet_ntop(AF_INET, &test_sa_check.sin_addr, i6buf, 1024); u_assert_str_eq(i6buf, "10.0.0.1"); /* create a inv message struct */ btc_p2p_inv_msg inv_msg, inv_msg_check; memset(&inv_msg, 0, sizeof(inv_msg)); uint256 hash = {0}; btc_p2p_msg_inv_init(&inv_msg, 1, hash); btc_p2p_msg_inv_ser(&inv_msg, inv_msg_cstr); struct const_buffer buf_inv = {inv_msg_cstr->str, inv_msg_cstr->len}; u_assert_int_eq(btc_p2p_msg_inv_deser(&inv_msg_check, &buf_inv), true); u_assert_int_eq(inv_msg_check.type, 1); u_assert_mem_eq(inv_msg_check.hash, inv_msg.hash, sizeof(inv_msg.hash)); cstr_free(inv_msg_cstr, true); /* create a version message struct */ btc_p2p_version_msg version_msg; memset(&version_msg, 0, sizeof(version_msg)); /* create a serialized version message */ btc_p2p_msg_version_init(&version_msg, &fromAddr, &toAddr, "client", false); btc_p2p_msg_version_ser(&version_msg, version_msg_cstr); /* create p2p message */ cstring *p2p_msg = btc_p2p_message_new((unsigned const char *)&btc_chainparams_main.netmagic, BTC_MSG_VERSION, version_msg_cstr->str, version_msg_cstr->len); struct const_buffer buf = {p2p_msg->str, p2p_msg->len}; btc_p2p_msg_hdr hdr; btc_p2p_deser_msghdr(&hdr, &buf); u_assert_mem_eq(hdr.netmagic, &btc_chainparams_main.netmagic, 4); u_assert_str_eq(hdr.command, BTC_MSG_VERSION); u_assert_int_eq(hdr.data_len, version_msg_cstr->len); u_assert_int_eq(buf.len, hdr.data_len); u_assert_int_eq(buf.len, hdr.data_len); u_assert_mem_eq(buf.p, version_msg_cstr->str, hdr.data_len); btc_p2p_version_msg v_msg_check; u_assert_int_eq(btc_p2p_msg_version_deser(&v_msg_check, &buf), true); u_assert_int_eq(v_msg_check.version, BTC_PROTOCOL_VERSION); u_assert_str_eq(v_msg_check.useragent, "client"); u_assert_int_eq(v_msg_check.start_height, 0); cstr_free(p2p_msg, true); cstr_free(version_msg_cstr, true); /* getheaders */ uint256 genesis_hash = {0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xd6, 0x68, 0x9c, 0x08, 0x5a, 0xe1, 0x65, 0x83, 0x1e, 0x93, 0x4f, 0xf7, 0x63, 0xae, 0x46, 0xa2, 0xa6, 0xc1, 0x72, 0xb3, 0xf1, 0xb6, 0x0a, 0x8c, 0xe2, 0x6f}; vector *blocklocators = vector_new(1, NULL); vector_add(blocklocators, genesis_hash); cstring *getheader_msg = cstr_new_sz(256); btc_p2p_msg_getheaders(blocklocators, NULL, getheader_msg); p2p_msg = btc_p2p_message_new((unsigned const char *)&btc_chainparams_main.netmagic, BTC_MSG_GETHEADERS, getheader_msg->str, getheader_msg->len); buf.p = p2p_msg->str; buf.len = p2p_msg->len; btc_p2p_deser_msghdr(&hdr, &buf); u_assert_str_eq(hdr.command, BTC_MSG_GETHEADERS); u_assert_int_eq(hdr.data_len, getheader_msg->len); uint256 hashstop_check; vector *blocklocators_check = vector_new(1, free); btc_p2p_deser_msg_getheaders(blocklocators_check, hashstop_check, &buf); u_assert_mem_eq(NULLHASH, hashstop_check, sizeof(hashstop_check)); uint8_t *hash_loc_0 = vector_idx(blocklocators_check, 0); u_assert_mem_eq(genesis_hash, hash_loc_0, sizeof(genesis_hash)); /* cleanup */ cstr_free(getheader_msg, true); vector_free(blocklocators, true); vector_free(blocklocators_check, true); cstr_free(p2p_msg, true); }
btc_bool btc_tx_sighash(const btc_tx* tx_to, const cstring* fromPubKey, unsigned int in_num, int hashtype, uint8_t* hash) { if (in_num >= tx_to->vin->len) return false; btc_bool ret = true; btc_tx* tx_tmp = btc_tx_new(); btc_tx_copy(tx_tmp, tx_to); cstring* new_script = cstr_new_sz(fromPubKey->len); btc_script_copy_without_op_codeseperator(fromPubKey, new_script); unsigned int i; btc_tx_in* tx_in; for (i = 0; i < tx_tmp->vin->len; i++) { tx_in = vector_idx(tx_tmp->vin, i); cstr_resize(tx_in->script_sig, 0); if (i == in_num) cstr_append_buf(tx_in->script_sig, new_script->str, new_script->len); } cstr_free(new_script, true); /* Blank out some of the outputs */ if ((hashtype & 0x1f) == SIGHASH_NONE) { /* Wildcard payee */ if (tx_tmp->vout) vector_free(tx_tmp->vout, true); tx_tmp->vout = vector_new(1, btc_tx_out_free_cb); /* Let the others update at will */ for (i = 0; i < tx_tmp->vin->len; i++) { tx_in = vector_idx(tx_tmp->vin, i); if (i != in_num) tx_in->sequence = 0; } } else if ((hashtype & 0x1f) == SIGHASH_SINGLE) { /* Only lock-in the txout payee at same index as txin */ unsigned int n_out = in_num; if (n_out >= tx_tmp->vout->len) { //TODO: set error code ret = false; goto out; } vector_resize(tx_tmp->vout, n_out + 1); for (i = 0; i < n_out; i++) { btc_tx_out* tx_out; tx_out = vector_idx(tx_tmp->vout, i); tx_out->value = -1; if (tx_out->script_pubkey) { cstr_free(tx_out->script_pubkey, true); tx_out->script_pubkey = NULL; } } /* Let the others update at will */ for (i = 0; i < tx_tmp->vin->len; i++) { tx_in = vector_idx(tx_tmp->vin, i); if (i != in_num) tx_in->sequence = 0; } } /* Blank out other inputs completely; not recommended for open transactions */ if (hashtype & SIGHASH_ANYONECANPAY) { if (in_num > 0) vector_remove_range(tx_tmp->vin, 0, in_num); vector_resize(tx_tmp->vin, 1); } cstring* s = cstr_new_sz(512); btc_tx_serialize(s, tx_tmp); ser_s32(s, hashtype); sha256_Raw((const uint8_t*)s->str, s->len, hash); sha256_Raw(hash, 32, hash); cstr_free(s, true); out: btc_tx_free(tx_tmp); return ret; }