A PHP Error was encountered

Severity: Warning

Message: file_put_contents(): Only 0 of 42 bytes written, possibly out of free disk space

Filename: libraries/article.php

Line Number: 212

A PHP Error was encountered

Severity: Warning

Message: mkdir(): File exists

Filename: libraries/menu.php

Line Number: 500

A PHP Error was encountered

Severity: Warning

Message: file_put_contents(/var/www/html/contents/menus/h_blogs/b_purenode/views/purenode whitepaper_0): failed to open stream: No such file or directory

Filename: libraries/menu.php

Line Number: 505

iadix blockchain platform - blogs Purenode whitepaper en

Iadix HTML 5.0 multichain technology
Blockchain, economic solutions and online business
A blockchain to link them all

Blogs Purenode article en

tags


purenode

Purenode whitepaper

author:BitAdmin (Registered)
articles:9
Join date:15/01/16 22:18




Purenode White Paper

Purenode is a modular blockchain engine, which can be adapted to either create new blockchain with customized feature from scratch, or be used as a wallet, masternode and block explorer for most coins.

 

Its design is very simple, programmed in C, and it uses a system of binary module which can be created out of dll or so files, and then loaded on any operating system with the same cpu architecture regardless of the locally installed runtime or libraries or the compiler used to produce them.

 

Bitcore use a monolithic architecture, and alternative blockchains are created by forking the source code tree, changing some hard - coded value and recompiling the core to make the new coin which often contain the masternode server, the block kernel and the wallet in a single application executable, with the hard-coded values specific for the coin compiled in.

 

The block explorer is yet another software bundle, typically based on node.js modules, using its own database synchronized with the blockchain node when the block explorer is first initialized, using a server side template system in javascript, working as a middleware between web browser and the blockchain to visualize blocks.

 

 

With purenode, a new blockchain can be created just by setting the coins parameters in a configuration file and running a new instance of the node without having to recompile or edit any code, and a block explorer with an address cache is already included with an html5 - javascript application connected directly to the node. A system of cache in php or another server side script language can be added for better performance.

 





It also include an html5 javascript wallet able to generate private key and sign transaction using javascript code, allowing maximum privacy, as the private key never leave the browser in clear form, and the only javascript code executing in the browser is able to decypher using user supplied secret, and use these private key to sign transaction right inside the browser. Nodes never have to manipulate or access private key, but still keep track of transaction on public addresses, allowing for read-only wallet for financial audit, like bitmonero watch-only wallet, and the private key manipulation and hash signing is made inside of the browser without the node knowing about the private key at all.

 



 

All the functionalities being modularized, it makes it very easy to adapt the code to specific blockchain needs, or add new functionalities by recompiling the binary module, which can be loaded on any operating system as long as the libcon library is compiled for this host. The design is small, < 32Mo of ram used, and <=1mo of binaries most of which are operating system agnostic.

 

The design rely on a framework of dynamic data tree, with an internal memory allocator that use reference counting mechanism rather than standard C allocation, which allow for easy sharing of data pointer between different modules without pointer ownership, and allow the same ease of programming than java like languages where there is no free of memory, but acquiring and releasing of objects references, the powerful system of dynamic data tree allow to represent a hierarchy of dynamically typed nodes, each node being explicitly typed and containing binary data and/or a list children references to other nodes.

 

 

 

 

 

 

The configuration file for the coin looks like this :

 

iadix.conf

{

"name":"purenode",
"seed_node_host":"iadix.com",
"seed_node_port":16714,
"p2p_port":16819,
"magic":0xD9BEFECA, 
"version":60018,
"sign_mod":"ecdsa",
"pubKeyVersion":0x19,

"staking":

{

"staking_kernel":"stake_pos3",
"target spacing":64,
"target timespan":960,
"stake reward":150000000,
limit:0x1B00FFFF

},
"mining":
{

"target spacing":64,
"target timespan":960,
"limit":0x1E0FFFFF,
"reward":10000000000000,
"last_pow_block":200,
"paytxfee":10000

},
"rpc_wallet":
{

"module":"rpc_wallet",
"rpc_port":16820,
"index":"/wallet",
"page file":"wallet.html"

},
"block_explorer":
{

"module":"block_explorer",
"base path":"/api/",
"page file":"blocks.html"

},
"genesis":
{

"version" :1,
"time" :1466419085,
"bits" :0x1e0fffff,
"nonce" :579883,
"InitialStakeModifier":0,
"InitialStakeModifier2":0

}}

 

The design rely on a framework of dynamic data tree, with an internal memory allocator that use reference counting mechanism rather than standard C allocation, which allow for easy sharing of data pointer between different modules without pointer ownership, and allow the same ease of programming that java like language where there is no free of memory, but aquiring and releasing of object reference, and the dynamic data tree allow to represent a hierarchy of typed node, each node has a type and a list of reference to other nodes.

 

The parsing of the configuration file looks like this :

 

mem_zone_ref node_config;

unsigned int node_port, seed_port;

struct string node_port_str;

struct string node_hostname;

 

node_port_str.str = PTR_NULL;

node_port_str.len = 0;

node_port_str.size = 0;

 

node_hostname.str = PTR_NULL;

node_hostname.len = 0;

node_hostname.size = 0;

 

node_config.zone = PTR_NULL;

 

if (get_file("iadix.conf", &data, &data_len)<=0)

{

log_message("unable to file iadix.conf\n", PTR_NULL);

return 0;

}

if (!tree_manager_json_loadb(data, data_len, &node_config))

{

free_c(data);

log_message("unable to parse node config\n", PTR_NULL);

return 0;

}

free_c(data);

 

tree_manager_get_child_value_istr (&node_config, NODE_HASH("seed_node_host"), &node_hostname, 0);

tree_manager_get_child_value_i32 (&node_config, NODE_HASH("seed_node_port"), &seed_port);

tree_manager_get_child_value_istr (&node_config, NODE_HASH("name"), &user_agent, 0);

 

tree_manager_create_node ("log", NODE_LOG_PARAMS, &log);

tree_manager_set_child_value_i32 (&log, "port", node_port);

tree_manager_set_child_value_str (&log, "hostname", node_hostname.str);

log_message ("node port %port% open @ %hostname% ", &log);

release_zone_ref (&log);

 

 

[1478705362] node port 28823827 open @ iadix.com

[1478705366] new message version, 35352084 playload : 100 bytes from iadix.com

:16714

[1478705368] new message verack, 38063939 playload : 0 bytes from iadix.com :16

714

[1478705368] node 82.165.128.213:16714 version 60018 network last block: 34962,

me 88.190.203.85:49352

 

[1478705370] new message ping, 15999093 playload : 8 bytes from iadix.com :1671

4

[1478705371] new message pong, 17993121 playload : 8 bytes from iadix.com :1671

4

[1478705371] block locator:

 

 

 

[1478705373] new message inv, 33129591 playload : 18003 bytes from iadix.com :1

6714

[1478705375] new message block, 18077154 playload : 174 bytes from iadix.com :1

6714

[1478705376] new message block, 90243950 playload : 174 bytes from iadix.com :1

6714

[1478705376] new modifier=22F4FEC149C9617A3AF5B34D506B4211DB61D2E0A6F1AA69AE409B

A222E47029 time=14671632 hash=A611A6783AA6FB83782A454CB11DB2A926E9CCA2678905F839

9ED3AF2B6749AF

[1478705376] ----------------

NEW POW BLOCK

00000FFFFF000000000000000000000000000000000000000000000000000000

00000ED287279BDB4CE0CB9B7E4611143FEB16E5ED4B897EC2B3CF876CFFA260

A611A6783AA6FB83782A454CB11DB2A926E9CCA2678905F8399ED3AF2B6749AF

 

[1478705376] accepted block: A611A6783AA6FB83782A454CB11DB2A926E9CCA2678905F8399

ED3AF2B6749AF , 14671632 - 7 EF96C4CB9CCEE2DDB15839634855DC3265BC028E8D91106740D

0B8EB39F64A18

 

[1478705376] block height : 2 , 223 – 247

 

[1478705292] new message block, 28088885 playload : 477 bytes from iadix.com :16714

[1478705292] new modifier=82059C1ECFF8189D08C69F37A9DBE26042332909D50A169DA564FA67DACA0C05 time=14671634 hash=9D1D236F101428B43471AF03DD54C6A1E394789497D2233423BA7E275FCDD861

[1478705292] ----------------

NEW POW BLOCK

0000033258000000000000000000000000000000000000000000000000000000

000001AEA84D7E7F6E9049BA000D402E2012FE964CF851ECBB667E36CEE9E163

9D1D236F101428B43471AF03DD54C6A1E394789497D2233423BA7E275FCDD861

 

[1478705292] accepted block: 9D1D236F101428B43471AF03DD54C6A1E394789497D2233423BA7E275FCDD861 , 14671634 - 7 D8DC3A8A9F57E0E8F3D0F9CCA1BF91B7F788935096633643D689D8BBA29F1E56

 

[1478705292] block height : 18

 

 

LIBCON ( has to be compiled for the host)

  • memory allocation of references pointer and basic memory manipulation.

  • string and basic text manipulation, utf8.

  • File system access and I/O.

  • Socket and network.

  • XML Parser (expat) used by uPnp.

  • Zlib for compression/decompression.

  • Binary module loader.

  • Base C runtime.

 

LIBBASE (distributed as system agnostic binary module)

  • Dynamic data tree based on references pointer.

  • HTTP protocol.

  • JSON parser.

  • UPNP

  • hashes (SHA256,MD5,RIP160)

 

PROTOCOL (distributed as source)

  • Parsing of bitcore protocol message as binary tree

  • Creation of new message using the bitcore protocol based on binary tree template.

 

BLOCK (distributed as source)

  • Function to check proof of work block header (based on the built-in hash algorithm)

  • Functions to manipulate and verify transactions.

  • Function to store block and transaction data

  • Function to store wallet transaction cache based on block transaction.

 

SIGNATURE (distributed as source)

  • Functions to generate key pairs

  • Functions to extract public key from private key

  • Function to sign data

  • Function to verify data signature

 

RPC WALLET(distributed as source)

  • Function to list json formatted data about the blockchain, compatible with bitcore RPC api, without the transaction signing related methods, which are implemented in a way to allow browser signing in javascript. (called from javascript wallet page).

 

BLOCK EXPLORER(distributed as source)

  • Block explorer web api functions to output json formatted data (called from javascript in the block explorer page).

 

NODE (distributed as system agnostic binary module)

  • Reception of network packet and data transmission to protocol module.

  • Emission of queued messages to other nodes on the network.

  • Loading of RPC server and block explorer module.

  • Handling of HTTP json/ajax/rpc request.

  • Handling of block index and current proof of work difficulty

 

Staking kernel (distributed as source)

  • Validation of proof of stake block and staking reward.

  • Storing of pos specific data on the local system.

  • Computing proof of stake difficulty re-targeting.

  • Generation of new proof of stake block template for staking.

 

COIN (distributed as source)

  • Loading of configuration file.

  • Initialization of the proof of stake kernel module.

  • Initialization of the node module.

  • Global coin logic and network message handling.

 

 

 

 



 

Coin core binary module

Node functions definition

 

 

 

typedef int C_API_FUNC node_init_self_func(mem_zone_ref_ptr out_self_node, mem_zone_ref_ptr node_config);

typedef int C_API_FUNC node_set_last_block_func(mem_zone_ref_ptr header);

typedef int C_API_FUNC node_load_last_blks_func();

typedef int C_API_FUNC node_find_last_pow_block_func(mem_zone_ref_ptr pindex, unsigned int *block_time);

typedef int C_API_FUNC node_is_next_block_func(mem_zone_ref_const_ptr header, mem_zone_ref_ptr lastBlk);

typedef int C_API_FUNC new_peer_node_func(struct host_def *host, mem_zone_ref_ptr peer_nodes);

typedef int C_API_FUNC node_add_block_func(mem_zone_ref_ptr header, mem_zone_ref_ptr txs, uint64_t staking_reward);

typedef int C_API_FUNC read_node_msg_func(mem_zone_ref_ptr node);

typedef int C_API_FUNC send_node_messages_func(mem_zone_ref_ptr node);

typedef int C_API_FUNC node_add_block_header_func(mem_zone_ref_ptr node, mem_zone_ref_ptr hdr);

typedef int C_API_FUNC queue_version_message_func(mem_zone_ref_ptr node, struct string *user_agent);

typedef int C_API_FUNC queue_verack_message_func(mem_zone_ref_ptr node);

typedef int C_API_FUNC queue_ping_message_func(mem_zone_ref_ptr node, uint64_t nonce);

typedef int C_API_FUNC queue_pong_message_func(mem_zone_ref_ptr node, uint64_t nonce);

typedef int C_API_FUNC queue_getaddr_message_func(mem_zone_ref_ptr node);

typedef int C_API_FUNC queue_getdata_message_func(mem_zone_ref_ptr node, mem_zone_ref_ptr hash_list);

typedef int C_API_FUNC queue_block_message_func(mem_zone_ref_ptr node, mem_zone_ref_ptr header, mem_zone_ref_ptr tx_list, struct string *signature);

typedef int C_API_FUNC queue_getblocks_message_func(mem_zone_ref_ptr node);

typedef int C_API_FUNC queue_getblock_hdrs_message_func(mem_zone_ref_ptr node);

typedef int C_API_FUNC queue_send_message_func(mem_zone_ref_ptr node, mem_zone_ref_ptr msg);

typedef int C_API_FUNC queue_emitted_element_func(mem_zone_ref_ptr node, mem_zone_ref_ptr element);

typedef int C_API_FUNC queue_emitted_message_func(mem_zone_ref_ptr node, mem_zone_ref_ptr msg);

typedef int C_API_FUNC node_init_rpc_func(mem_zone_ref_ptr in_config,tpo_mod_file *pos);

typedef int C_API_FUNC check_rpc_request_func();

typedef int C_API_FUNC node_init_block_explorer_func(mem_zone_ref_ptr in_config, tpo_mod_file *pos_mod);

typedef int C_API_FUNC node_add_block_index_func(hash_t hash, unsigned int time);

typedef int C_API_FUNC queue_inv_message_func(mem_zone_ref_ptr node, mem_zone_ref_ptr hash_list);

 

 

 

Staking Kernel function definition

 

typedef int C_API_FUNC init_pos_func(mem_zone_ref_ptr stake_conf);

typedef int C_API_FUNC store_blk_staking_func(mem_zone_ref_ptr header,mem_zone_ref_ptr tx_list);

typedef int C_API_FUNC store_tx_staking_func(mem_zone_ref_ptr tx, hash_t tx_hash, btc_addr_t stake_addr, uint64_t stake_in);

typedef int C_API_FUNC compute_blk_staking_func(mem_zone_ref_ptr prev, mem_zone_ref_ptr prevPOS, mem_zone_ref_ptr hdr, mem_zone_ref_ptr tx_list, uint64_t *staking_reward);

typedef int C_API_FUNC compute_last_pos_diff_func(mem_zone_ref_ptr lastPOS, unsigned int *nBits);

typedef int C_API_FUNC load_last_pos_blk_func(mem_zone_ref_ptr header);

typedef int C_API_FUNC store_last_pos_hash_func(hash_t hash);

typedef int C_API_FUNC find_last_pos_block_func(mem_zone_ref_ptr pindex, unsigned int *block_time);

typedef unsigned int C_API_FUNC get_current_pos_difficulty_func();

 

 

 

 

 

 

Base initialization

 

OS_API_C_FUNC(int) app_init(mem_zone_ref_ptr params)

{

mem_zone_ref log = { PTR_NULL };

unsigned char *data;

size_t data_len;

 

tree_manager_init(8*1024*1024);

 

node_port_str.str = PTR_NULL;

node_port_str.len = 0;

node_port_str.size = 0;

 

node_hostname.str = PTR_NULL;

node_hostname.len = 0;

node_hostname.size = 0;

 

node_config.zone = PTR_NULL;

init_string(&user_agent);

peer_nodes.zone = PTR_NULL;

memset_c(null_hash, 0, 32);

 

 

if (get_file("iadix.conf", &data, &data_len)<=0)

{

log_message("unable to file iadix.conf\n", PTR_NULL);

return 0;

}

 

if (!tree_manager_json_loadb(data, data_len, &node_config))

{

free_c(data);

log_message("unable to parse node config\n", PTR_NULL);

return 0;

}

free_c(data);

 

 

tree_manager_get_child_value_istr(&node_config, NODE_HASH("seed_node_host"), &node_hostname, 0);

tree_manager_get_child_value_i32(&node_config, NODE_HASH("seed_node_port"), &seed_port);

tree_manager_get_child_value_istr(&node_config, NODE_HASH("name"), &user_agent, 0);

 

self_node.zone = PTR_NULL;

 

create_dir("adrs");

create_dir("txs");

create_dir("blks");

 

load_node_module(&node_config);

if (!node_init_self(&self_node, &node_config))

{

console_print("unable to init self node \n");

return 0;

}

 

tree_manager_create_node("log", NODE_LOG_PARAMS, &log);

tree_manager_set_child_value_i32(&log, "port", node_port);

tree_manager_set_child_value_str(&log, "hostname", node_hostname.str);

log_message("node port %port% open @ %hostname% ", &log);

release_zone_ref(&log);

 

return 1;

}

Application start

 

 

OS_API_C_FUNC(int) app_start(mem_zone_ref_ptr params)

{

mem_zone_ref genesis = { PTR_NULL };

mem_zone_ref log = { PTR_NULL };

mem_zone_ref seed_node = { PTR_NULL }, rpc_wallet_conf = { PTR_NULL }

mem_zone_ref block_explorer_conf = { PTR_NULL }, genesis_conf = { PTR_NULL }, stake_conf = { PTR_NULL };

struct host_def *seed_host;

int nc;

 

if (!tree_manager_find_child_node(&node_config, NODE_HASH("genesis"), 0xFFFFFFFF, &genesis_conf))

{

log_message("no genesis block in node config\n", PTR_NULL);

return 0;

}

 

make_genesis_block(&genesis_conf, &genesis);

if (tree_manager_find_child_node(&node_config, NODE_HASH("staking"), 0xFFFFFFFF, &stake_conf))

{

char staking_kernel[33];

tree_manager_get_child_value_str(&stake_conf, NODE_HASH("staking_kernel"), staking_kernel, 33, 0);

if (load_pos_module(staking_kernel, &pos_kernel))

{

init_pos(&stake_conf);

store_blk_staking(&genesis, PTR_NULL);

}

release_zone_ref(&stake_conf);

}

else

memset_c(&pos_kernel, 0, sizeof(tpo_mod_file));

 

nc = get_last_block_height();

if (nc < 1)

{

hash_t h;

unsigned int t;

tree_manager_get_child_value_hash (&genesis, NODE_HASH("blk hash"), h);

tree_manager_get_child_value_i32 (&genesis, NODE_HASH("time"), &t);

node_set_last_block (&genesis);

node_add_block_index (h,t);

}

release_zone_ref(&genesis_conf);

release_zone_ref(&genesis);

 

seed_host = make_host_def(node_hostname.str, seed_port);

tree_manager_create_node("peer nodes", NODE_BITCORE_NODE_LIST, &peer_nodes);

if (!new_peer_node(seed_host, &peer_nodes))

{

free_string(&node_port_str);

free_string(&node_hostname);

free_host_def(seed_host);

return 0;

}

free_host_def(seed_host);

 

reset_addr_scan();

 

 if (tree_manager_find_child_node(&node_config, NODE_HASH("rpc_wallet"), 0xFFFFFFFF, &rpc_wallet_conf))

{

node_init_rpc (&rpc_wallet_conf,&pos_kernel);

release_zone_ref (&rpc_wallet_conf);

}

 

if (tree_manager_find_child_node(&node_config, NODE_HASH("block_explorer"), 0xFFFFFFFF, &block_explorer_conf))

{

node_init_block_explorer (&block_explorer_conf, &pos_kernel);

release_zone_ref (&block_explorer_conf);

}

 

 

if (nc > 1)

{

mem_zone_ref last_blk = { PTR_NULL };

mem_zone_ref lastPOSBlk = { PTR_NULL }, lastPOWBlk = { PTR_NULL };

unsigned int nBits;

node_load_last_blks();

 

 

tree_manager_find_child_node(&self_node, NODE_HASH("last block"), NODE_BITCORE_BLK_HDR, &last_blk);

 

//compute current block difficulty

if (tree_manager_find_child_node(&self_node, NODE_HASH("last pow block"), NODE_BITCORE_BLK_HDR, &lastPOWBlk))

{

if (compute_last_pow_diff(&lastPOWBlk, &nBits))

tree_manager_set_child_value_i32(&self_node, "current pow diff", nBits);

else

{

tree_manager_get_child_value_i32(&last_blk, NODE_HASH("bits"), &nBits);

tree_manager_set_child_value_i32(&self_node, "current pow diff", nBits);

}

release_zone_ref(&lastPOWBlk);

}

 

if (strlen_c(pos_kernel.name) > 0)

{

unsigned int time, nBits;

 

if (tree_manager_create_node("last pos block", NODE_BITCORE_BLK_HDR, &lastPOSBlk))

{

if (load_last_pos_blk(&lastPOSBlk))

tree_manager_node_add_child(&self_node, &lastPOSBlk);

else if (last_blk.zone != PTR_NULL)

{

copy_zone_ref(&lastPOSBlk, &last_blk);

if (find_last_pos_block(&lastPOSBlk, &time))

{

hash_t h;

tree_manager_get_child_value_hash(&lastPOSBlk, NODE_HASH("blk hash"), h);

store_last_pos_hash(h);

tree_manager_node_add_child(&self_node, &lastPOSBlk);

}

else

copy_zone_ref(&lastPOSBlk, &last_blk);

}

 

if (compute_last_pos_diff(&lastPOSBlk, &nBits))

tree_manager_set_child_value_i32(&self_node, "current pos diff", nBits);

else

{

tree_manager_get_child_value_i32(&self_node, NODE_HASH("limit"), &nBits);

tree_manager_set_child_value_i32(&self_node, "current pos diff", nBits);

}

 

 

log_message("loaded last block pos %blk hash%", &lastPOSBlk);

release_zone_ref(&lastPOSBlk);

}

}

release_zone_ref(&last_blk);

}

 

tree_manager_get_child_at(&peer_nodes, 0, &seed_node);

queue_version_message(&seed_node, &user_agent);

release_zone_ref(&seed_node);

synching = 0;

return 1;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Application main loop

 

OS_API_C_FUNC(int) app_loop(mem_zone_ref_ptr params)

{

mem_zone_ref blk_list = { PTR_NULL };

mem_zone_ref my_list = { PTR_NULL };

mem_zone_ref hash_list = { PTR_NULL };

mem_zone_ref_ptr blk = PTR_NULL;

unsigned int new_block = 0;

 

update_nodes();

process_nodes();

 

tree_manager_create_node("hashes", NODE_BITCORE_HASH_LIST, &hash_list);

if (tree_manager_find_child_node(&self_node, NODE_HASH("submitted blocks"), NODE_BITCORE_BLK_HDR_LIST, &blk_list))

{

for (tree_manager_get_first_child(&blk_list, &my_list, &blk); ((blk != NULL) && (blk->zone != NULL)); tree_manager_get_next_child(&my_list, &blk))

{

hash_t blk_hash = { 0 };

struct string signature = { PTR_NULL };

mem_zone_ref tx_list = { PTR_NULL };

unsigned int is_signed;

int ret;

 

if (!tree_manager_find_child_node(blk, NODE_HASH("txs"), NODE_BITCORE_TX_LIST, &tx_list))continue;

if (!tree_manager_get_child_value_istr(blk, NODE_HASH("signature"), &signature, 0))continue;

 

ret=accept_block (blk, &tx_list,&signature);

if (ret)

{

mem_zone_ref new_hash = { PTR_NULL };

 

tree_manager_get_child_value_hash(blk, NODE_HASH("blk hash"), blk_hash);

if (tree_manager_add_child_node(&hash_list, "hash", NODE_BITCORE_BLOCK_HASH, &new_hash))

{

tree_manager_write_node_hash(&new_hash, 0, blk_hash);

release_zone_ref(&new_hash);

}

new_block = 1;

}

release_zone_ref (&tx_list);

free_string (&signature);

tree_manager_set_child_value_bool (blk, "done", 1);

}

tree_remove_child_by_member_value_dword(&blk_list, NODE_BITCORE_BLK_HDR, "done", 1);

release_zone_ref(&blk_list);

}

if (new_block)

{

mem_zone_ref_ptr node = PTR_NULL;

for (tree_manager_get_first_child(&peer_nodes, &my_list, &node); ((node != NULL) && (node->zone != NULL)); tree_manager_get_next_child(&my_list, &node))

{

queue_inv_message(node, &hash_list);

}

}

release_zone_ref(&hash_list);

return 1;

}

Processing of node I/O

 

int update_nodes()

{

mem_zone_ref_ptr node = PTR_NULL;

mem_zone_ref my_list = { PTR_NULL };

 

for (tree_manager_get_first_child(&peer_nodes, &my_list, &node); ((node != PTR_NULL) && (node->zone != PTR_NULL)); tree_manager_get_next_child(&my_list, &node))

{

send_node_messages (node);

read_node_msg (node);

check_rpc_request ();

}

return 1;

}

 

Processing of node parsed messages

 

int handle_message(mem_zone_ref_ptr node,const char *cmd,mem_zone_ref_ptr payload)

{

if (!strncmp_c(cmd, "verack", 6)){ return handle_verack(node,payload); }

if (!strncmp_c(cmd, "version", 7))return handle_version(node, payload);

if (!strncmp_c(cmd, "ping", 4))return handle_ping(node, payload);

if (!strncmp_c(cmd, "pong", 4))return handle_pong(node, payload);

if (!strncmp_c(cmd, "addr", 4))return handle_addr(node, payload);

if (!strncmp_c(cmd, "inv", 3))return handle_inv(node, payload);

if (!strncmp_c(cmd, "block", 5))return handle_block(node, payload);

if (!strncmp_c(cmd, "getdata", 7))return handle_getdata(node, payload);

return 0;

}

int process_node_messages(mem_zone_ref_ptr node)

{

mem_zone_ref msg_list = { PTR_NULL };

mem_zone_ref_ptr msg = PTR_NULL;

mem_zone_ref my_list = { PTR_NULL };

unsigned int nc;

 

if (!tree_manager_find_child_node(node, NODE_HASH("emitted queue"), NODE_BITCORE_MSG_LIST, &msg_list))return 0;

 

for ( tree_manager_get_first_child(&msg_list, &my_list, &msg);

((msg != NULL) && (msg->zone != NULL));

tree_manager_get_next_child(&my_list, &msg))

{

char cmd[16];

mem_zone_ref payload_node = { PTR_NULL };

int ret;

 

if (!tree_manager_get_child_value_str(msg, NODE_HASH("cmd"), cmd, 12, 16))continue;

tree_manager_find_child_node(msg, NODE_HASH("payload"), NODE_BITCORE_PAYLOAD, &payload_node);

ret = handle_message(node, cmd, &payload_node);

tree_manager_set_child_value_i32(msg, "handled", ret);

release_zone_ref(&payload_node);

}

tree_remove_children(&msg_list);

nc = tree_manager_get_node_num_children(&msg_list);

release_zone_ref(&msg_list);

return 1;

}

 

 

 

int process_nodes()

{

mem_zone_ref_ptr node = PTR_NULL;

mem_zone_ref my_list = { PTR_NULL };

 

for (

tree_manager_get_first_child(&peer_nodes, &my_list, &node);

(node != NULL) && (node->zone != NULL);

tree_manager_get_next_child(&my_list, &node))

{

ctime_t next_check;

ctime_t curtime;

process_node_messages(node);

if (synching == 1)

{

curtime = get_time_c();

if (tree_manager_get_child_value_i64(node, NODE_HASH("next_check"), &next_check))

{

if (curtime >= next_check)

{

queue_getblocks_message(node);

tree_manager_set_child_value_i32(node, "next_check", curtime + 5);

}

}

}

}

return 1;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Sample processing of some messages

 

 

int handle_version(mem_zone_ref_ptr node, mem_zone_ref_ptr payload)

{

char user_agent[32];

mem_zone_ref log = { PTR_NULL }, block_index_node = { PTR_NULL };

unsigned int proto_ver, last_blk, node_port,my_port;

mem_zone_ref addrs[2] = { PTR_NULL };

uint64_t time, services, timestamp;

int index = 0;

ipv4_t node_ip,my_ip;

uint64_t nblks;

 

tree_manager_get_child_value_i32 (payload, NODE_HASH("proto_ver"), &proto_ver);

tree_manager_get_child_value_i64 (payload, NODE_HASH("timestamp"), &time);

tree_manager_get_child_value_i64 (payload, NODE_HASH("services"), &services);

tree_manager_get_child_value_i64 (payload, NODE_HASH("timestamp"), ×tamp);

tree_manager_get_child_value_str (payload, NODE_HASH("user_agent"),user_agent, 32, 16);

tree_manager_get_child_value_i32 (payload, NODE_HASH("last_blk"), &last_blk);

 

index = 1;

tree_node_list_child_by_type (payload, NODE_BITCORE_ADDR, &addrs[0], 0);

tree_node_list_child_by_type (payload, NODE_BITCORE_ADDR, &addrs[1], 1);

 

tree_manager_get_child_value_ipv4 (&addrs[0], NODE_HASH("addr"), my_ip);

tree_manager_get_child_value_i32 (&addrs[0], NODE_HASH("port"), &my_port);

 

tree_manager_get_child_value_ipv4 (&addrs[1], NODE_HASH("addr"), node_ip);

tree_manager_get_child_value_i32 (&addrs[1], NODE_HASH("port"), &node_port);

 

 

tree_manager_create_node("log", NODE_LOG_PARAMS, &log);

tree_manager_set_child_value_ipv4(&log, "nip", node_ip);

tree_manager_set_child_value_i32(&log, "nport", node_port);

tree_manager_set_child_value_ipv4(&log, "ip", my_ip);

tree_manager_set_child_value_i32(&log, "port", my_port);

tree_manager_set_child_value_str(&log, "services", services ? "network" : "no services");

tree_manager_set_child_value_i32(&log, "version", proto_ver);

tree_manager_set_child_value_str(&log, "user_agent", user_agent);

tree_manager_set_child_value_i32(&log, "lastblk", last_blk);

log_message("node %nip%:%nport% version %version% %services% last block: %lastblk%, me %ip%:%port% \n", &log);

release_zone_ref(&log);

 

 

release_zone_ref(&addrs[0]);

release_zone_ref(&addrs[1]);

 

 

 

 

 

 

queue_verack_message (node);

  queue_getaddr_message (node);

 

 if (!tree_manager_get_child_value_i64(&self_node, NODE_HASH("block height"), &nblks))

nblks = 0;

 

if (nblks > (last_blk + 1))

{

mem_zone_ref hash_list = { PTR_NULL };

if (tree_manager_create_node("hashes", NODE_BITCORE_HASH_LIST, &hash_list))

{

int num = 1000;

while (last_blk < nblks)

{

if ((num--) == 0)break;

if (tree_manager_find_child_node(&self_node, NODE_HASH("block index"), NODE_BITCORE_HASH, &block_index_node))

{

hash_t hash;

if (tree_manager_get_node_hash(&block_index_node, last_blk*sizeof(hash_t), hash))

{

mem_zone_ref new_hash = { PTR_NULL };

if (tree_manager_add_child_node(&hash_list, "hash", NODE_BITCORE_BLOCK_HASH, &new_hash))

{

tree_manager_write_node_hash(&new_hash, 0, hash);

release_zone_ref(&new_hash);

}

}

release_zone_ref(&block_index_node);

}

last_blk++;

}

queue_inv_message(node, &hash_list);

release_zone_ref(&hash_list);

}

}

return 1;

}

 

int handle_ping(mem_zone_ref_ptr node, mem_zone_ref_ptr payload)

{

uint64_t nonce;

tree_manager_get_child_value_i64(payload, NODE_HASH("nonce"), &nonce);

queue_pong_message (node, nonce);

return 1;

}

 

 

 

int handle_pong(mem_zone_ref_ptr node, mem_zone_ref_ptr payload)

{

synching = 1;

return 1;

}

 

 

 

int handle_verack(mem_zone_ref_ptr node, mem_zone_ref_ptr payload)

{

queue_ping_message(node,ping_nonce++);

return 1;

}

 

 

 

 

 

int handle_addr(mem_zone_ref_ptr node, mem_zone_ref_ptr payload)

{

mem_zone_ref log = { PTR_NULL };

mem_zone_ref addr_list = { PTR_NULL };

mem_zone_ref my_list = { PTR_NULL };

mem_zone_ref_ptr addr;

 

tree_manager_find_child_node(payload, NODE_HASH("addrs"), NODE_BITCORE_ADDR_LIST, &addr_list);

for (tree_manager_get_first_child(&addr_list, &my_list, &addr); ((addr != NULL) && (addr->zone != NULL)); tree_manager_get_next_child(&my_list, &addr))

{

unsigned int time;

uint64_t services;

ipv4_t ip;

unsigned short port;

 

tree_manager_get_child_value_i32 (addr, NODE_HASH("time") , &time);

tree_manager_get_child_value_i64 (addr, NODE_HASH("services"), &services);

 

tree_manager_get_child_value_ipv4 (addr, NODE_HASH("addr") , ip);

tree_manager_get_child_value_i16 (addr, NODE_HASH("port") , &port);

 

tree_manager_create_node("log", NODE_LOG_PARAMS, &log);

tree_manager_set_child_value_ipv4(&log, "ip", ip);

tree_manager_set_child_value_i32(&log, "port", port);

tree_manager_set_child_value_str(&log, "services", services ? "network" : "no services");

tree_manager_set_child_value_i32(&log, "time", time);

log_message("new address %ip%:%port% %time% %services%\n", &log);

release_zone_ref(&log);

}

release_zone_ref(&addr_list);

return 1;

}

 

 

 

 

 

int handle_inv(mem_zone_ref_ptr node, mem_zone_ref_ptr payload)

{

mem_zone_ref hash_list = { PTR_NULL };

tree_manager_find_child_node(payload, NODE_HASH("hashes"), NODE_BITCORE_HASH_LIST, &hash_list);

queue_getdata_message(node, &hash_list);

release_zone_ref(&hash_list);

return 1;

}

 

 

 

 

 

 

 

 

 

 

 

int accept_block(mem_zone_ref_ptr header, mem_zone_ref_ptr tx_list, struct string *signature)

{

hash_t blk_hash;

mem_zone_ref log = { PTR_NULL };

struct string sign = { PTR_NULL };

uint64_t block_reward = 0, staking_reward = 0, nblks;

int ret = 1, is_staking;

mem_zone_ref lastPOSBlk = { PTR_NULL }, lastPOWBlk = { PTR_NULL }, lastBlk = { PTR_NULL };

 

if (!node_is_next_block(header, &lastBlk))

return 0;

 

tree_manager_get_child_value_i64(&self_node, NODE_HASH("block height"), &nblks);

compute_block_hash(header, blk_hash);

tree_manager_set_child_value_bhash(header, "blk hash", blk_hash);

 

if (strlen_c(pos_kernel.name) > 0)

{

mem_zone_ref sig = { PTR_NULL };

tree_manager_find_child_node (&self_node, NODE_HASH("last pos block"), NODE_BITCORE_BLK_HDR, &lastPOSBlk);

 

if (!tree_manager_find_child_node(header, NODE_HASH("signature"), NODE_BITCORE_ECDSA_SIG, &sig))

tree_manager_add_child_node (header, "signature", NODE_BITCORE_ECDSA_SIG, &sig);

 

tree_manager_write_node_sig (&sig, 0, signature->str, signature->len);

release_zone_ref (&sig);

 

ret = compute_blk_staking (&lastBlk, &lastPOSBlk, header, tx_list, &block_reward);

release_zone_ref (&lastPOSBlk);

}

tree_manager_find_child_node(&self_node, NODE_HASH("last pos block"), NODE_BITCORE_BLK_HDR, &lastPOSBlk);

 

if (find_hash(blk_hash))

remove_block(blk_hash);

 

if (ret)

{

hash_t out_diff;

unsigned int powbits;

if (block_reward == 0)

{

if (!tree_manager_get_child_value_i32(&self_node, NODE_HASH("current pow diff"), &powbits))

tree_manager_get_child_value_i32(header, NODE_HASH("bits"), &powbits);

 

SetCompact(powbits, out_diff);

ret = check_block_pow(header, out_diff);

if (ret)

block_reward = get_blockreward(nblks);

 

is_staking = 0;

}

else

{

is_staking = 1;

}

}

 

 

if (ret)

ret = node_add_block(header, tx_list, block_reward);

 

if (ret)

{

unsigned int blocktime = 0;

 

if (strlen_c(pos_kernel.name) > 0)

store_blk_staking(header, tx_list);

 

tree_manager_get_child_value_i32(header, NODE_HASH("time"), &blocktime);

 

if (is_staking)

{

mem_zone_ref last_blk = { PTR_NULL };

unsigned int pBits;

 

store_last_pos_hash(blk_hash);

 

if (!tree_manager_find_child_node(&self_node, NODE_HASH("last pos block"), NODE_BITCORE_BLK_HDR, &last_blk))

tree_manager_add_child_node(&self_node, "last pos block", NODE_BITCORE_BLK_HDR, &last_blk);

 

tree_manager_copy_children_ref(&last_blk, header);

release_zone_ref(&last_blk);

 

if (compute_last_pos_diff(header, &pBits))

tree_manager_set_child_value_i32(&self_node, "current pos diff", pBits);

else

tree_manager_set_child_value_i32(&self_node, "current pos diff", 0x1FFFFFFF);

}

else

{

unsigned int powbits;

 

if (compute_last_pow_diff(header, &powbits))

tree_manager_set_child_value_i32(&self_node, "current pow diff", powbits);

else

{

tree_manager_get_child_value_i32(header, NODE_HASH("bits"), &powbits);

tree_manager_set_child_value_i32(&self_node, "current pow diff", powbits);

}

 

}

node_add_block_index(blk_hash, blocktime);

add_moneysupply(block_reward);

}

release_zone_ref(&lastBlk);

return ret;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

int handle_getdata(mem_zone_ref_ptr node, mem_zone_ref_ptr payload)

{

mem_zone_ref hash_list = { PTR_NULL }, my_list = { PTR_NULL };

mem_zone_ref_ptr hash_node;

unsigned int data_type = 0;

if (!tree_manager_find_child_node(payload, NODE_HASH("hashes"), NODE_BITCORE_HASH_LIST, &hash_list))return 0;

 

for (

tree_manager_get_first_child(&hash_list, &my_list, &hash_node);

((hash_node != NULL) && (hash_node->zone != NULL));

tree_manager_get_next_child(&my_list, &hash_node))

{

char chash[65];

hash_t hash;

mem_zone_ref block = { PTR_NULL }, txs = { PTR_NULL };

unsigned char *hash_data;

hash_data = tree_mamanger_get_node_data_ptr(hash_node, 0);

if (tree_mamanger_get_node_type(hash_node) == NODE_BITCORE_BLOCK_HASH)

{

int n = 32;

while (n--)hash[n] = hash_data[31 - n];

n = 0;

while (n<32)

{

chash[n * 2 + 0] = hex_chars[hash_data[n] >> 4];

chash[n * 2 + 1] = hex_chars[hash_data[n] & 0x0F];

n++;

}

chash[64] = 0;

}

 

if (load_blk_hdr(&block, chash))

{

if (tree_manager_create_node("txs", NODE_BITCORE_TX_LIST, &txs))

{

struct string sign = { 0 };

get_blk_sign(chash, &sign);

 

if (load_blk_txs(chash, &txs))

queue_block_message (node, &block, &txs,&sign);

 

free_string(&sign);

release_zone_ref(&txs);

}

release_zone_ref(&block);

}

}

release_zone_ref(&hash_list);

return 1;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

int handle_block(mem_zone_ref_ptr node, mem_zone_ref_ptr payload)

{

mem_zone_ref header = { PTR_NULL }, tx_list = { PTR_NULL }, sig = { PTR_NULL };

mem_zone_ref log = { PTR_NULL };

size_t nz1 = 0, nz2 = 0;

struct string signature = { PTR_NULL };

int ret = 1;

uint64_t nblks;

 

if (!tree_manager_find_child_node(payload, NODE_HASH("header"), NODE_BITCORE_BLK_HDR, &header))return 0;

if (!tree_manager_find_child_node(payload, NODE_HASH("txs"), NODE_BITCORE_TX_LIST, &tx_list)){ release_zone_ref(&header); return 0; }

if (!tree_manager_find_child_node(payload, NODE_HASH("signature"), NODE_BITCORE_ECDSA_SIG, &sig)){ release_zone_ref(&tx_list); release_zone_ref(&header); return 0; }

 

tree_manager_get_node_istr (&sig, 0, &signature,0);

release_zone_ref (&sig);

 

ret = accept_block (&header, &tx_list, &signature);

 

 

if (ret)

log_message("accepted block: %blk hash% , %time% - %version% %merkle_root%\n", &header);

else

log_message("rejected block: %blk hash% , %time% - %version% %merkle_root%\n", &header);

 

tree_manager_set_child_value_i64(node, "next_check", get_time_c() + 10);

 

 

tree_manager_get_child_value_i64(&self_node, NODE_HASH("block height"), &nblks);

tree_manager_create_node("log", NODE_LOG_PARAMS, &log);

tree_manager_set_child_value_i32(&log, "nblocks", nblks);

log_message("block height : %nblocks%\n", &log);

release_zone_ref(&log);

 

free_string(&signature);

release_zone_ref(&header);

release_zone_ref(&tx_list);

 

return ret;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Sample processing of rpc request

 

 

OS_API_C_FUNC(int) liststaking(mem_zone_ref_const_ptr params, unsigned int rpc_mode, mem_zone_ref_ptr result)

{

mem_zone_ref_ptr addr;

mem_zone_ref minconf = { PTR_NULL }, maxconf = { PTR_NULL }, unspents = { PTR_NULL }, addrs = { PTR_NULL };

mem_zone_ref my_list = { PTR_NULL };

mem_zone_ref last_blk = { PTR_NULL };

struct string pos_hash_data = { PTR_NULL };

int max = 2000;

int ret = 0;

unsigned int block_time;

unsigned int target,iminconf=0;

if (!tree_manager_find_child_node(&my_node, NODE_HASH("last block"), NODE_BITCORE_BLK_HDR, &last_blk))return 0;

 

if (!tree_manager_add_child_node(result, "unspents", NODE_JSON_ARRAY, &unspents))

return 0;

 

if (tree_manager_get_child_at(params, 0, &minconf))

{

tree_mamanger_get_node_dword(&minconf, 0, &iminconf);

release_zone_ref (&minconf);

}

 

if (iminconf < min_staking_depth)

iminconf = min_staking_depth;

 

tree_manager_get_child_at (params, 1, &maxconf);

tree_manager_get_child_at (params, 2, &addrs);

 

get_target_spacing (&target);

tree_manager_get_child_value_i32(&last_blk, NODE_HASH("time"), &block_time);

 

tree_manager_set_child_value_i32(result, "block_target", target);

tree_manager_set_child_value_i32(result, "now", get_time_c());

tree_manager_set_child_value_i32(result, "last_block_time", block_time);

 

for (tree_manager_get_first_child(&addrs, &my_list, &addr); ((addr != NULL) && (addr->zone != NULL)); tree_manager_get_next_child(&my_list, &addr))

{

if (max > 0)

{

btc_addr_t my_addr;

tree_manager_get_node_btcaddr(addr, 0, my_addr);

list_staking_unspent(&last_blk, my_addr, &unspents, iminconf, &max);

}

}

release_zone_ref(&last_blk);

release_zone_ref(&unspents);

release_zone_ref(&addrs);

release_zone_ref(&maxconf);

 

 

return 1;

 

}

 

 

 

 

OS_API_C_FUNC(int) signstakeblock(mem_zone_ref_const_ptr params, unsigned int rpc_mode, mem_zone_ref_ptr result)

{

hash_t rblkHash, blkHash;

unsigned char chash[65];

struct string signature = { 0 }, vpubk = { 0 }, pubk = { 0 }, sign = { 0 };

mem_zone_ref pn = { PTR_NULL }, blk = { PTR_NULL }, node_blks = { PTR_NULL };

unsigned int n;

int ret=0;

tree_manager_get_child_at(params, 0, &pn);

tree_manager_get_node_str(&pn, 0, chash, 65, 0);

release_zone_ref(&pn);

 

tree_manager_get_child_at(params, 1, &pn);

tree_manager_get_node_istr(&pn, 0, &signature, 0);

release_zone_ref(&pn);

 

tree_manager_get_child_at(params, 2, &pn);

tree_manager_get_node_istr(&pn, 0, &vpubk, 0);

release_zone_ref(&pn);

 

n = 0;

while (n < 32)

{

char hex[3];

hex[0] = chash[n * 2 + 0];

hex[1] = chash[n * 2 + 1];

hex[2] = 0;

blkHash[n] = strtoul_c(hex, PTR_NULL, 16);

rblkHash[31 - n] = blkHash[n];

n++;

}

 

sign.len = signature.len / 2;

sign.size = sign.len + 1;

sign.str = malloc_c(sign.size);

n = 0;

while (n < sign.len)

{

char hex[3];

hex[0] = signature.str[n * 2 + 0];

hex[1] = signature.str[n * 2 + 1];

hex[2] = 0;

sign.str[n] = strtoul_c(hex, PTR_NULL, 16);

n++;

}

sign.str[sign.len] = 0;

free_string(&signature);

 

 

if (vpubk.len == 66)

{

pubk.len = 33;

pubk.size = pubk.len + 1;

pubk.str = malloc_c(pubk.size);

n = 0;

while (n < pubk.len)

{

char hex[3];

hex[0] = vpubk.str[n * 2 + 0];

hex[1] = vpubk.str[n * 2 + 1];

hex[2] = 0;

pubk.str[n] = strtoul_c(hex, PTR_NULL, 16);

n++;

}

pubk.str[pubk.len] = 0;

}

free_string(&vpubk);

 

if (tree_manager_find_child_node(&my_node, NODE_HASH("submitted blocks"), NODE_BITCORE_BLK_HDR_LIST, &node_blks))

{

if (tree_find_child_node_by_member_name_hash(&node_blks, NODE_BITCORE_BLK_HDR, "blk hash", blkHash, &blk))

{

mem_zone_ref txs = { PTR_NULL };

mem_zone_ref sig = { PTR_NULL };

 

if (pubk.len==0)

ret = 1;

else

{

unsigned char type;

struct string bsig = { 0 };

 

ret = parse_sig_seq(&sign, &bsig, &type, 1);

if (ret)

ret = blk_check_sign(&bsig, &pubk, blkHash);

}

if (ret)

{

tree_manager_add_child_node(&blk, "signature", NODE_BITCORE_ECDSA_SIG, &sig);

tree_manager_write_node_sig(&sig, 0, sign.str, sign.len);

release_zone_ref(&sig);

}

release_zone_ref (&blk);

}

release_zone_ref(&node_blks);

}

 

free_string(&sign);

free_string(&pubk);

 

 

return ret;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

OS_API_C_FUNC(int) signstaketx(mem_zone_ref_const_ptr params, unsigned int rpc_mode, mem_zone_ref_ptr result)

{

hash_t txHash;

unsigned char chash[65];

btc_addr_t pubAddr;

int ret = 0;

unsigned int n;

unsigned char hash_type = 1;

struct string bsign = { PTR_NULL }, sign = { PTR_NULL };

mem_zone_ref pn = { PTR_NULL }, node_txs = { PTR_NULL }, tx = { PTR_NULL };

 

tree_manager_get_child_at (params, 0, &pn);

tree_manager_get_node_str (&pn, 0, chash, 65, 0);

release_zone_ref (&pn);

 

n = 0;

while (n < 32)

{

char hex[3];

hex[0] = chash[n * 2 + 0];

hex[1] = chash[n * 2 + 1];

hex[2] = 0;

txHash[n] = strtoul_c(hex, PTR_NULL, 16);

n++;

}

 

tree_manager_get_child_at (params, 1, &pn);

tree_manager_get_node_istr (&pn, 0, &sign, 0);

release_zone_ref (&pn);

bsign.len = (sign.len / 2)+1;

bsign.size = bsign.len + 1;

bsign.str = malloc_c(bsign.size);

 

n = 0;

while (n < bsign.len)

{

char hex[3];

hex[0] = sign.str[n * 2 + 0];

hex[1] = sign.str[n * 2 + 1];

hex[2] = 0;

bsign.str[n] = strtoul_c(hex, PTR_NULL, 16);

n++;

}

free_string(&sign);

 

bsign.str[bsign.len-1] = hash_type;

 

 tree_manager_get_child_at (params, 2, &pn);

tree_manager_get_node_btcaddr (&pn, 0, pubAddr);

release_zone_ref (&pn);

 

 if (tree_manager_find_child_node(&my_node, NODE_HASH("tx mem pool"), NODE_BITCORE_TX_LIST, &node_txs))

{

if (tree_find_child_node_by_member_name_hash(&node_txs, NODE_BITCORE_TX, "tx hash", txHash, &tx))

{

mem_zone_ref last_blk = { PTR_NULL }, newBlock = { PTR_NULL };

ret = tx_sign(&tx, 0, hash_type, &bsign);

if (ret)

{

if (tree_manager_find_child_node(&my_node, NODE_HASH("last block"), NODE_BITCORE_BLK_HDR, &last_blk))

{

hash_t block_hash;

tree_manager_get_child_value_hash(&last_blk, NODE_HASH("blk hash"), block_hash);

if (create_pos_block(block_hash, &tx, &newBlock))

{

mem_zone_ref txs = { PTR_NULL }, blk_list = { PTR_NULL };

 

if (tree_manager_find_child_node(&my_node, NODE_HASH("submitted blocks"), NODE_BITCORE_BLK_HDR_LIST, &blk_list))

{

hash_t h,rblkh;

 

tree_manager_get_child_value_hash(&newBlock, NODE_HASH("blk hash"), h);

n = 32;

while (n--)rblkh[n] = h[31 - n];

 

tree_manager_set_child_value_hash (result , "newblockhash", rblkh);

tree_manager_node_add_child (&blk_list , &newBlock);

release_zone_ref (&blk_list);

}

release_zone_ref(&newBlock);

}

release_zone_ref(&last_blk);

}

}

release_zone_ref(&tx);

}

release_zone_ref(&node_txs);

}

free_string(&bsign);

return ret;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

OS_API_C_FUNC(int) getstaketx(mem_zone_ref_const_ptr params, unsigned int rpc_mode, mem_zone_ref_ptr result)

{

unsigned char chash[65];

hash_t txHash, blkhash;

btc_addr_t pubaddr;

char toto = 0;

mem_zone_ref vout = { PTR_NULL }, prevtx = { PTR_NULL }, newtx = { PTR_NULL }, pn = { PTR_NULL };

struct string sPubk = { PTR_NULL }, script = { PTR_NULL }, null_str = { PTR_NULL };

uint64_t amount;

unsigned int OutIdx, newTxTime,n;

int ret;

 

null_str.str = &toto;

null_str.len = 0;

null_str.size = 1;

 

tree_manager_get_child_at (params, 0, &pn);

tree_manager_get_node_str (&pn, 0, chash, 65, 0);

release_zone_ref (&pn);

 

n = 0;

while (n < 32)

{

char hex[3];

hex[0] = chash[n * 2 + 0];

hex[1] = chash[n * 2 + 1];

hex[2] = 0;

txHash[31 - n] = strtoul_c(hex, PTR_NULL, 16);

n++;

}

 

tree_manager_get_child_at (params, 1, &pn);

tree_mamanger_get_node_dword (&pn, 0, &OutIdx);

release_zone_ref (&pn);

 

tree_manager_get_child_at (params, 2, &pn);

tree_mamanger_get_node_dword (&pn, 0, &newTxTime);

release_zone_ref (&pn);

 

ret = load_tx(&prevtx, blkhash, txHash);

 

if (ret)

ret = get_tx_output(&prevtx, OutIdx, &vout);

if (ret)

ret = tree_manager_get_child_value_istr(&vout, NODE_HASH("script"), &script, 0);

if (ret)

ret = tree_manager_get_child_value_i64(&vout, NODE_HASH("value"), &amount);

 

get_out_script_address(&script, &sPubk, pubaddr);

 

if (ret)

{

uint64_t half_am,rew;

ret = 0;

get_stake_reward (&rew);

half_am = muldiv64 (amount+rew, 1, 2);

if (tree_manager_add_child_node(result, "transaction", NODE_BITCORE_TX, &newtx))

{

hash_t txh;

unsigned int hash_type = 1;

 

if (new_transaction(&newtx, newTxTime))

{

mem_zone_ref last_blk = { PTR_NULL };

hash_t StakeMod, pos_hash, out_diff;

hash_t prevOutHash;

uint64_t weight;

unsigned int prevOutIdx,last_diff;

unsigned int ModTime;

 

tx_add_input (&newtx, txHash, OutIdx, &script);

tx_add_output(&newtx, 0, &null_str);

tx_add_output(&newtx, half_am, &script);

tx_add_output(&newtx, half_am, &script);

tree_manager_find_child_node(&my_node, NODE_HASH("last block"), NODE_BITCORE_BLK_HDR, &last_blk))

get_last_stake_modifier(&last_blk, StakeMod, &ModTime);

compute_tx_pos(&newtx,StakeMod,newTxTime,pos_hash, prevOutHash, &prevOutIdx );

memset_c (out_diff, 0, sizeof(hash_t));

get_tx_output_amount (prevOutHash, prevOutIdx, &weight);

last_diff = get_current_pos_difficulty();

if (last_diff == 0xFFFFFFFF)

{

unsigned int nBits;

tree_manager_get_child_value_i32(&last_blk, NODE_HASH("bits"), &nBits);

mul_compact(nBits, weight, out_diff);

}

else

mul_compact(last_diff, weight, out_diff);

 

//check proof of stake

if (cmp_hashle(pos_hash, out_diff) >= 0)

{

hash_t rtxhash;

mem_zone_ref node_txs = { PTR_NULL };

 

compute_tx_sign_hash (&newtx, 0, &script, hash_type, txh);

 

n = 32;

while (n--)rtxhash[n] = txh[31 - n];

tree_manager_set_child_value_hash (result, "txhash" , rtxhash);

tree_manager_set_child_value_btcaddr(result, "addr" , pubaddr);

if (tree_manager_find_child_node(&my_node, NODE_HASH("tx mem pool"), NODE_BITCORE_TX_LIST, &node_txs))

{

tree_manager_set_child_value_bhash(&newtx, "tx hash", txh);

tree_manager_node_add_child (&node_txs, &newtx);

release_zone_ref (&node_txs);

}

ret = 1;

}

}

release_zone_ref(&newtx);

}

}

release_zone_ref(&vout);

release_zone_ref(&prevtx);

free_string(&script);

return ret;

}

 

 

OS_API_C_FUNC(int) getstaking(mem_zone_ref_const_ptr params, unsigned int rpc_mode, mem_zone_ref_ptr result)

{

mem_zone_ref last_blk = { PTR_NULL };

struct string pos_hash_data = { PTR_NULL };

int ret = 0;

 

if (tree_manager_find_child_node(&my_node, NODE_HASH("last block"), NODE_BITCORE_BLK_HDR, &last_blk))

{

unsigned char chash[65];

hash_t txHash, out_diff;

mem_zone_ref pn = { PTR_NULL };

unsigned int OutIdx, target, block_time,n;

uint64_t amount;

 

tree_manager_get_child_at (params, 0, &pn);

tree_manager_get_node_str (&pn, 0, chash,65, 0);

release_zone_ref (&pn);

 

n = 0;

while (n < 32)

{

char hex[3];

hex[0] = chash[n * 2 + 0];

hex[1] = chash[n * 2 + 1];

hex[2] = 0;

txHash[31-n]= strtoul_c(hex, PTR_NULL, 16);

n++;

}

 

tree_manager_get_child_at(params, 1, &pn);

tree_mamanger_get_node_dword(&pn, 0, &OutIdx);

release_zone_ref(&pn);

 

get_target_spacing (&target);

tree_manager_get_child_value_i32(&last_blk, NODE_HASH("time"), &block_time);

 

memset_c(out_diff, 0, sizeof(hash_t));

 

if (get_tx_pos_hash_data(&last_blk, txHash, OutIdx, &pos_hash_data, &amount, out_diff))

{

hash_t rout_diff;

 

n = 32;

while (n--)rout_diff[n]=out_diff[31 - n];

 

tree_manager_set_child_value_str (result , "hash_data" , pos_hash_data.str);

tree_manager_set_child_value_hash(result , "difficulty" , rout_diff);

tree_manager_set_child_value_i64(result , "weight" , amount);

tree_manager_set_child_value_i32 (result , "block_target" , target);

tree_manager_set_child_value_i32 (result , "now" , get_time_c());

tree_manager_set_child_value_i32 (result , "last_block_time", block_time);

ret = 1;

}

free_string (&pos_hash_data);

release_zone_ref(&last_blk);

}

return ret;

}

 

 

 

OS_API_C_FUNC(int) importkeypair(mem_zone_ref_const_ptr params, unsigned int rpc_mode, mem_zone_ref_ptr result)

{

btc_addr_t pubaddr;

dh_key_t pub, priv;

mem_zone_ref username_n = { PTR_NULL }, pubkey_n = { PTR_NULL }, privkey_n = { PTR_NULL };

struct string username = { PTR_NULL }, xpubkey = { PTR_NULL }, xprivkey = { PTR_NULL };

struct string user_key_file = { PTR_NULL };

size_t keys_data_len = 0;

unsigned char *keys_data = PTR_NULL;

int found;

 

tree_manager_get_child_at(params, 0, &username_n);

tree_manager_get_child_at(params, 1, &pubkey_n);

tree_manager_get_child_at(params, 2, &privkey_n);

tree_manager_get_node_istr(&username_n, 0, &username, 0);

tree_manager_get_node_istr(&pubkey_n, 0, &xpubkey, 0);

tree_manager_get_node_istr(&privkey_n, 0, &xprivkey, 0);

release_zone_ref(&privkey_n);

release_zone_ref(&pubkey_n);

release_zone_ref(&username_n);

 

if (xpubkey.len == 66)

{

int n = 33;

while (n--)

{

char hex[3];

hex[0] = xpubkey.str[n * 2 + 0];

hex[1] = xpubkey.str[n * 2 + 1];

hex[2] = 0;

pub[n] = strtoul_c(hex, PTR_NULL, 16);

}

key_to_addr(pub, pubaddr);

}

 

memset_c(priv, 0, sizeof(dh_key_t));

if ((xprivkey.len > 0) && (xprivkey.len <= sizeof(dh_key_t)))

{

int n = xprivkey.len;

while (n--)

{

char hex[3];

hex[0] = xprivkey.str[n * 2 + 0];

hex[1] = xprivkey.str[n * 2 + 1];

hex[2] = 0;

priv[n] = strtoul_c(hex, PTR_NULL, 16);

}

}

 

create_dir("keypairs");

make_string(&user_key_file, "keypairs");

cat_cstring_p(&user_key_file, username.str);

 

found = 0;

 

if (get_file(user_key_file.str, &keys_data, &keys_data_len))

{

mem_ptr keys_ptr = keys_data;

while (keys_data_len > 0)

{

if (!memcmp_c(keys_ptr, pubaddr, sizeof(btc_addr_t)))

{

found = 1;

break;

}

keys_ptr = mem_add(keys_ptr, (sizeof(btc_addr_t) + sizeof(dh_key_t)));

keys_data_len -= (sizeof(btc_addr_t) + sizeof(dh_key_t));

}

free_c(keys_data);

}

 

if (!found)

{

mem_zone_ref tx_list = { PTR_NULL }, my_list = { PTR_NULL };

mem_zone_ref_ptr tx = PTR_NULL;

 

append_file(user_key_file.str, pubaddr, sizeof(btc_addr_t));

append_file(user_key_file.str, priv, sizeof(dh_key_t));

if (tree_manager_create_node("txs", NODE_BITCORE_HASH_LIST, &tx_list))

{

struct string adr_path = { 0 };

make_string(&adr_path, "adrs");

cat_ncstring_p(&adr_path, pubaddr, 34);

if (stat_file(adr_path.str) == 0)

{

struct string path = { 0 };

clone_string(&path, &adr_path);

cat_cstring_p(&path, "spent");

rm_dir(path.str);

free_string(&path);

 

clone_string(&path, &adr_path);

cat_cstring_p(&path, "unspent");

rm_dir(path.str);

free_string(&path);

 

clone_string(&path, &adr_path);

cat_cstring_p(&path, "stakes");

del_file(path.str);

free_string(&path);

}

 

create_dir(adr_path.str);

free_string(&adr_path);

 

load_tx_addresses(pubaddr, &tx_list);

for (

tree_manager_get_first_child(&tx_list, &my_list, &tx);

((tx != NULL) && (tx->zone != NULL));

tree_manager_get_next_child(&my_list, &tx))

{

hash_t tx_hash;

 

tree_manager_get_node_hash(tx, 0, tx_hash);

store_tx_wallet(pubaddr, tx_hash);

}

release_zone_ref(&tx_list);

}

 

}

free_string(&user_key_file);

free_string(&username);

free_string(&xpubkey);

free_string(&xprivkey);

return 1;

}

 

 

OS_API_C_FUNC(int) getprivaddr(mem_zone_ref_const_ptr params, unsigned int rpc_mode, mem_zone_ref_ptr result)

{

mem_zone_ref pn = { PTR_NULL }, addr_list = { PTR_NULL };

struct string pubaddr = { PTR_NULL }, username = { PTR_NULL };

struct string user_key_file = { PTR_NULL };

unsigned char *keys_data = PTR_NULL;

size_t keys_data_len = 0;

int ret = 0;

 

tree_manager_get_child_at (params, 0, &pn);

tree_manager_get_node_istr (&pn, 0, &username, 0);

release_zone_ref (&pn);

 

tree_manager_get_child_at (params, 1, &pn);

tree_manager_get_node_istr (&pn, 0, &pubaddr, 0);

release_zone_ref (&pn);

 

make_string (&user_key_file, "keypairs");

cat_cstring_p (&user_key_file, username.str);

if (get_file(user_key_file.str, &keys_data, &keys_data_len))

{

unsigned char *keys_ptr = keys_data;

while (keys_data_len > 0)

{

if (!strncmp_c(keys_ptr, pubaddr.str , sizeof(btc_addr_t)))

{

char hexk[129];

int n=0;

while (n < 64)

{

hexk[n * 2 + 0] = hex_chars[keys_ptr[sizeof(btc_addr_t) + n] >> 4];

hexk[n * 2 + 1] = hex_chars[keys_ptr[sizeof(btc_addr_t) + n] & 0x0F];

n++;

}

hexk[64] = 0;

ret = 1;

tree_manager_set_child_value_str(result, "privkey", hexk);

break;

}

keys_ptr = mem_add(keys_ptr, (sizeof(btc_addr_t) + sizeof(dh_key_t)));

keys_data_len -= (sizeof(btc_addr_t) + sizeof(dh_key_t));

}

free_c(keys_data);

}

free_string(&pubaddr);

free_string(&username);

free_string(&user_key_file);

return ret;

}

 

 

 

OS_API_C_FUNC(int) getpubaddrs(mem_zone_ref_const_ptr params, unsigned int rpc_mode, mem_zone_ref_ptr result)

{

mem_zone_ref username_n = { PTR_NULL }, addr_list = { PTR_NULL };

struct string username = { PTR_NULL };

struct string user_key_file = { PTR_NULL };

size_t keys_data_len = 0;

uint64_t conf_amount, unconf_amount, minconf;

unsigned char *keys_data = PTR_NULL;

 

if (!tree_manager_add_child_node(result, "addrs", NODE_JSON_ARRAY, &addr_list))

return 0;

 

tree_manager_get_child_at(params, 0, &username_n);

tree_manager_get_node_istr(&username_n, 0, &username, 0);

release_zone_ref(&username_n);

 

make_string(&user_key_file, "keypairs");

cat_cstring_p(&user_key_file, username.str);

 

minconf = 1;

 

if (get_file(user_key_file.str, &keys_data, &keys_data_len))

{

mem_ptr keys_ptr=keys_data;

while (keys_data_len > 0)

{

mem_zone_ref new_addr = { PTR_NULL };

conf_amount = 0;

unconf_amount = 0;

 

get_balance (keys_ptr, &conf_amount, &unconf_amount, minconf);

if(tree_manager_add_child_node(&addr_list, "addr" , NODE_GFX_OBJECT, &new_addr))

{

tree_manager_set_child_value_btcaddr(&new_addr , "address", keys_ptr);

tree_manager_set_child_value_i64(&new_addr, "amount" , conf_amount);

tree_manager_set_child_value_i64(&new_addr, "unconf_amount", unconf_amount);

release_zone_ref(&new_addr);

}

keys_ptr = mem_add(keys_ptr ,(sizeof(btc_addr_t) + sizeof(dh_key_t)));

keys_data_len -= (sizeof(btc_addr_t) + sizeof(dh_key_t));

}

free_c(keys_data);

}

 

release_zone_ref (&addr_list);

free_string (&user_key_file);

free_string (&username);

return 1;

}

 

 

 

 

 

 

 

 

 

 

Sample javascript staking code in the browser

 

 

<script src="/ecdsa_bundle.js">script>

<script src="/jsSHA-2.2.0/src/sha_dev.js">script>

<script src="/jquery-3.1.1.min.js">script>

<script language="javascript">

var username = h0bby1 ;

var secret= 1234 ;

var ec;

var addrs = null;

var unspents = null;

var stake_unspents = null;

var totalweight = 0;

var pubkey;

var privkey;

var unit = 1;

var staketimer = null;

var block_target, now, last_block_time;

var nHashes=0;

 

 

function rpc_call(in_method, in_params, in_success) {

$.ajax({

url: /jsonrpc ,

data: JSON.stringify({ jsonrpc: 2.0 , method: in_method, params: in_params, id: 1 }), // id is needed !!

type: "POST",

dataType: "json",

success: in_success,

error: function (err) { alert("Error"); }

});

}

 

function staking_loop(hash_data, time_start, time_end, diff) {

var ct;

for (ct = time_start; ct < time_end; ct+=16)

{

str = hex32(ct);

total = hash_data + str;

h = sha256(total);

h2 = sha256(h);

 

if (compare_hash(h2, diff))

{

console.log( staking found + ct + + h2 + + diff);

$( #newhash ).html(h2);

return ct;

}

nHashes++;

}

return 0;

}

 

 

 

 

 

 

 

 

 

function check_all_staking() {

if ($( #do_staking ).prop( checked ))

{

if (stake_unspents != null)

{

var n;

var time_start, time_end;

var timeStart = Math.floor(new Date().getTime() / 1000);

var timeBegin = Math.floor((timeStart + 15) / 16) * 16;

var num_stake_unspents = stake_unspents.length;

if (last_block_time > (now - block_target)) {

time_start = Math.floor((last_block_time + 15) / 16) * 16;

time_end = time_start + block_target;

}

else {

time_start = timeBegin - 16;

time_end = timeBegin + 16;

}

nHashes = 0;

for (n = 0; n < num_stake_unspents; n++)

{

var txtime,staking;

staking = stake_unspents[n];

txtime=staking_loop(staking.hash_data, time_start, time_end, staking.difficulty);

if (txtime > 0)

{

rpc_call( getstaketx , [staking.txid, staking.vout, txtime], function (staketx)

{

var txh,txa;

txh = staketx.result.txhash;

txa = staketx.result.addr;

rpc_call( getprivaddr , [username, txa], function (keyData) {

var skey = decryptKey (keyData.result.privkey,secret);

keys = ec.keyPair({ priv: skey, privEnc: hex });

// Sign message (must be an array, or it ll be treated as a hex sequence)

var signature = keys.sign(txh, hex );

// Export DER encoded signature in Array

var derSign = signature.toLowS();

rpc_call( signstaketx , [txh, derSign], function (txsign) {

var hash = txsign.result.newblockhash;

var blocksignature = keys.sign(hash, hex );

// Export DER encoded signature in Array

var derSign = blocksignature.toLowS();

var pubk=keys.getPublic().encodeCompressed( hex );

rpc_call( signstakeblock , [hash, derSign, pubk], function (blksign) {});

});

});

});

$( #do_staking ).prop( checked , false);

return 0;

}

}

var timeEnd = Math.ceil(new Date().getTime() / 1000);

var timespan = (timeEnd-timeStart);

var hashrate = nHashes / timespan;

$( #hashrate ).html(nHashes + hashes in + timespan + secs ( + hashrate + hashes/sec) );

}

}

staketimer = setTimeout(check_all_staking, 10000);

}

 

function list_staking(addresses) {

var old_tbody = document.getElementById("list_table").tBodies[0];

var new_tbody = document.createElement( tbody );

old_tbody.parentNode.replaceChild(new_tbody, old_tbody);

rpc_call( liststaking , [0, 9999999, addresses], function (data) {

var total = 0;

var n;

stake_unspents = data.result.unspents;

block_target = data.result.block_target;

now = data.result.now;

last_block_time = last_block_time;

$( #do_staking ).prop( disabled , false);

 

for (n = 0; n < stake_unspents.length; n++)

{

total += stake_unspents[n].weight;

}

totalweight = total;

$( #stakeweight ).html(totalweight / unit);

$( #nstaketxs ).html(stake_unspents.length);

staketimer = setTimeout(check_all_staking, 10000);

 

});

}

 

function get_addrs(username) {

rpc_call( getpubaddrs , [username], function (data) {

var n;

var arAddr=[];

addrs = data.result.addrs;

update_addrs();

 

for (n = 0; n < addrs.length; n++) {

arAddr[n] = addrs[n].address;

}

list_unspent(arAddr);

list_staking(arAddr);

});

}

 

 

$(document).ready(function () {

ec = new EC( secp256k1 );

generateKeys();

get_addrs(username);

});

 

 

script>




comments
HTML 5 DOC