区块信息:
https://www.blockchain.com/zh/btc/block-height/20000
区块头格式:
共80个字节,上图中都是字符串,需要转换为二进制的区块头格式。
字段 | 大小 | 描述 |
---|---|---|
version | 04字节 | 版本号 |
previous block hash | 32字节 | 前一个区块的哈希 |
merkle root | 32字节 | 该区块中交易的merkle树根的哈希值 |
time | 04字节 | 该区块的创建时间戳 utc时间 |
bits | 04字节 | 该区块链工作量证明难度目标 |
nonce | 04字节 | 用于证明工作量的计算随机数 |
程序思路
1、通过区块链浏览器提供的api,获取一个区块的信息。
这里使用btc.com,以btc的创世块为例。
curl -s https://chain.api.btc.com/v3/block/0
{
"data": {
"height": 0,
"version": 1,
"mrkl_root": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
"timestamp": 1231006505,
"bits": 486604799,
"nonce": 2083236893,
"hash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
"prev_block_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"next_block_hash": "00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048",
"size": 285,
"pool_difficulty": 2536,
"difficulty": 1,
"tx_count": 1,
"reward_block": 5000000000,
"reward_fees": 0,
"created_at": 1488909332,
"confirmations": 552468,
"is_orphan": false,
"curr_max_timestamp": 1231006505,
"is_sw_block": false,
"stripped_size": 285,
"weight": 1140,
"extras": {
"pool_name": "unknown",
"pool_link": ""
}
},
"err_no": 0,
"err_msg": null
}
2、解析出区块的头部信息,生成结果block_header_t,注意各种字节序的转换。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
block:0
version:1
prev_block_hash:0000000000000000000000000000000000000000000000000000000000000000
mrkl_root:3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a
timestamp:1231006505
bits:486604799
nonce:2083236893
hash:000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3、系统的字节序为小端,80个字节的区块头部信息如下:
0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c
4、对区块头部进行2次哈希得到最终结果。
sha256-1=af42031e805ff493a07341e2f74ff58149d22ab9ba19f61343e2c86c71c5d66d
sha256-2=000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
完整的代码
// xmain.c
// by maxzero
#include "xutils.h"
#include "xsha256.h"
typedef struct _block_header {
uint32_t ver;
uint32_t hash_prev[8];
uint32_t hash_mkrt[8];
uint32_t timex;
uint32_t bits ;
uint32_t nonce;
}block_header_t;
static int make_block_header(block_header_t *block_header, int block_num)
{
FILE* f = NULL;
int n = 0;
int r = 0;
char url[1024];
char* buf = NULL;
int len = 1*1024*1024*sizeof(char);;
char temp[128];
memset(url, 0x00, sizeof(url));
sprintf(url, "curl -s https://chain.api.btc.com/v3/block/%d", block_num);
f = popen(url, "r");
buf = (char*)malloc(len);
if (NULL == buf) {
xprint_err("malloc() failed. len=%d\n", len);
pclose(f);
return -1;
}
memset(buf, 0x00, len);
n = fread(buf, 1, len, f);
if (n <= 0) {
xprint_err("fread() failed. n=%d\n", n);
goto xexit;
}
printf("n=%d l=%d\n", n, len);
printf("%s\n\n", buf);
memset(temp, 0x00, sizeof(temp));
if (-1 == xkey_value_parser(buf, "\"version\":", ",", temp, sizeof(temp))) {
r = -1;
goto xexit;
}
else {
block_header->ver = atoi(temp);
}
memset(temp, 0x00, sizeof(temp));
if (-1 == xkey_value_parser(buf, "\"mrkl_root\":\"", "\",", temp, sizeof(temp))) {
r = -1;
goto xexit;
}
else {
hex2bin((uint8_t*)block_header->hash_mkrt, temp, strlen(temp));
xreverse_dword((uint32_t*)block_header->hash_mkrt, 8, 1);
}
memset(temp, 0x00, sizeof(temp));
if (-1 == xkey_value_parser(buf, "\"timestamp\":", ",", temp, sizeof(temp))) {
r = -1;
goto xexit;
}
else {
block_header->timex = atoi(temp);
}
memset(temp, 0x00, sizeof(temp));
if (-1 == xkey_value_parser(buf, "\"bits\":", ",", temp, sizeof(temp))) {
r = -1;
goto xexit;
}
else {
block_header->bits = atoi(temp);
}
memset(temp, 0x00, sizeof(temp));
if (-1 == xkey_value_parser(buf, "\"nonce\":", ",", temp, sizeof(temp))) {
r = -1;
goto xexit;
}
else {
block_header->nonce = atoi(temp);
}
memset(temp, 0x00, sizeof(temp));
if (-1 == xkey_value_parser(buf, "\"prev_block_hash\":\"", "\",", temp, sizeof(temp))) {
r = -1;
goto xexit;
}
else {
hex2bin((uint8_t*)block_header->hash_prev, temp, strlen(temp));
xreverse_dword((uint32_t*)block_header->hash_prev, 8, 1);
}
memset(temp, 0x00, sizeof(temp));
if (-1 == xkey_value_parser(buf, "\"hash\":\"", "\",", temp, sizeof(temp))) {
r = -1;
goto xexit;
}
printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
printf(" block:%u\n", block_num);
printf(" version:%u\n", block_header->ver);
printf("prev_block_hash:"); xdump_byte((uint8_t*)block_header->hash_prev, 32, 32, 0);
printf(" mrkl_root:"); xdump_byte((uint8_t*)block_header->hash_mkrt, 32, 32, 0);
printf(" timestamp:%u\n", block_header->timex);
printf(" bits:%u\n", block_header->bits);
printf(" nonce:%u\n", block_header->nonce);
printf(" hash:%s\n", temp);
printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
printf("\n");
xexit:
free(buf);
pclose(f);
return r;
}
int hash_block_header(int block_num)
{
block_header_t block_header;
uint32_t sha1[8];
uint32_t sha2[8];
int i = 0;
memset(&block_header, 0x00, sizeof(block_header));
if (0 != make_block_header(&block_header, block_num)) {
return -1;
}
xdump_byte((uint8_t*)&block_header, 80, 80, 0);
xsha256((uint8_t*)&block_header, 80, sha1);
printf("sha256-1=");
for (i=0; i<8; i++) {
printf("%08x", sha1[i]);
sha1[i] = htonl(sha1[i]);
}
printf("\n");
xsha256((uint8_t*)sha1, sizeof(sha1), sha2);
xreverse_dword(sha2, 8, 1);
printf("sha256-2=");
for (i=0; i<8; i++) {
printf("%08x", sha2[i]);
}
printf("\n");
printf("\n");
return 0;
}
int main(int argc, char* argv[])
{
int block_num = 0;
if (argc != 2) {
printf("usage: a.out [block number]\n");
printf(" ex: a.out 100\n");
return -1;
}
block_num = atoi(argv[1]);
hash_block_header(block_num);
return 0;
}
// xsha256.h
// by maxzero
#ifndef _M_XSHA256_H
#define _M_XSHA256_H
#include "xutils.h"
#ifdef __cplusplus
extern "C" {
#endif
int xsha256(const uint8_t *src, uint32_t len, uint32_t *hash);
#ifdef __cplusplus
}
#endif
#endif
////////////////////////////////////////////////////////////////////////////////
// xsha256.c
// by maxzero
#include "xsha256.h"
#define XSHA_DBG 0
#define SHFR(x, n) (((x) >> (n)))
#define ROTR(x, n) (((x) >> (n)) | ((x) << ((sizeof(x) << 3) - (n))))
#define ROTL(x, n) (((x) << (n)) | ((x) >> ((sizeof(x) << 3) - (n))))
#define CHX(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
#define MAJ(x, y, z) (((x) & (y)) ^ ( (x) & (z)) ^ ((y) & (z)))
#define BSIG0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define BSIG1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define SSIG0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3))
#define SSIG1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))
#define SHA256_BLOCK_SIZE (512/8)
#define SHA256_COVER_SIZE (SHA256_BLOCK_SIZE*2)
static uint32_t k[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
static int xtransform(const uint8_t *msg, uint32_t *h)
{
uint32_t w[64];
uint32_t a0, b1, c2, d3, e4, f5, g6, h7;
uint32_t t1, t2;
int i = 0;
int j = 0;
for (i=0; i<16; i++) {
w[i] = msg[j]<<24 | msg[j+1]<<16 | msg[j+2]<<8 | msg[j+3];
j += 4;
}
for(i=16; i<64; i++){
w[i] = SSIG1(w[i-2])+w[i-7]+SSIG0(w[i-15])+w[i-16];
}
#if XSHA_DBG
xdump_byte((uint8_t*)w, 64*4, 32);
#endif
a0 = h[0];
b1 = h[1];
c2 = h[2];
d3 = h[3];
e4 = h[4];
f5 = h[5];
g6 = h[6];
h7 = h[7];
for (i= 0; i<64; i++) {
t1 = h7 + BSIG1(e4) + CHX(e4, f5, g6) + k[i] + w[i];
t2 = BSIG0(a0) + MAJ(a0, b1, c2);
h7 = g6;
g6 = f5;
f5 = e4;
e4 = d3 + t1;
d3 = c2;
c2 = b1;
b1 = a0;
a0 = t1 + t2;
}
h[0] += a0;
h[1] += b1;
h[2] += c2;
h[3] += d3;
h[4] += e4;
h[5] += f5;
h[6] += g6;
h[7] += h7;
return 0;
}
int xsha256(const uint8_t *src, uint32_t len, uint32_t *hash)
{
uint8_t *tmp = (uint8_t*)src;
uint8_t cover_data[SHA256_COVER_SIZE];
uint32_t cover_size = 0;
uint32_t i = 0;
uint32_t n = 0;
uint32_t m = 0;
uint32_t h[8];
h[0] = 0x6a09e667;
h[1] = 0xbb67ae85;
h[2] = 0x3c6ef372;
h[3] = 0xa54ff53a;
h[4] = 0x510e527f;
h[5] = 0x9b05688c;
h[6] = 0x1f83d9ab;
h[7] = 0x5be0cd19;
memset(cover_data, 0x00, sizeof(uint8_t)*SHA256_COVER_SIZE);
n = len / SHA256_BLOCK_SIZE;
m = len % SHA256_BLOCK_SIZE;
if (m < 56 ) {
cover_size = SHA256_BLOCK_SIZE;
}else {
cover_size = SHA256_BLOCK_SIZE*2;
}
if (m !=0) {
memcpy(cover_data, tmp + (n * SHA256_BLOCK_SIZE), m);
}
cover_data[m] = 0x80;
cover_data[cover_size-4] = ((len*8)&0xff000000) >> 24;
cover_data[cover_size-3] = ((len*8)&0x00ff0000) >> 16;
cover_data[cover_size-2] = ((len*8)&0x0000ff00) >> 8;
cover_data[cover_size-1] = ((len*8)&0x000000ff);
#if XSHA_DBG
xdump_hex(tmp, len-m, 32);
xdump_hex(cover_data, cover_size, 32);
#endif
for (i=0; i
// xutils.h
// by maxzero
#ifndef _M_XUTILS_H
#define _M_XUTILS_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef __cplusplus
extern "C" {
#endif
#define xdbg 1
#if xdbg
#define xprint_log(fmt, ...) \
printf("[%s:%04d] %s() " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)
#define xprint_err(fmt, ...) \
printf("[%s:%04d] %s() err: " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)
#else
#define xprint_log(fmt, ...)
#define xprint_err(fmt, ...)
#endif
#define XDUMP_LINEN 0x01
#define XDUMP_SPACE 0x02
#define XDEMP_DEFAULT (XDUMP_SPACE|XDUMP_LINEN)
int xdump_byte(const uint8_t *data, int size, int line, int flag);
uint8_t crc5(uint8_t *data, uint8_t size);
bool hex2bin(unsigned char *binstr, const char *hexstr, size_t len);
void xreverse_byte(unsigned char *s, size_t n);
void xreverse_dword(uint32_t *s, size_t n, int f);
int xkey_value_parser(char *data, char *key, char *end, char *value, int len);
#ifdef __cplusplus
}
#endif
#endif
/////////////////////////////////////////////////////////////////////////////////
// xutils.c
// by maxzero
#include "xutils.h"
static const int hex2bin_tbl[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};
int xdump_byte(const uint8_t *data, int size, int line, int flag)
{
int i;
int l = line;
if (size <= 0) { return 0; }
for (i=0; i> 1;
k++;
if (k == 8) {
j = 0x80;
k = 0;
data++;
}
memcpy(crcin, crcout, 5);
}
crc = 0;
if(crcin[4]) crc |= 0x10;
if(crcin[3]) crc |= 0x08;
if(crcin[2]) crc |= 0x04;
if(crcin[1]) crc |= 0x02;
if(crcin[0]) crc |= 0x01;
return crc;
}
bool hex2bin(unsigned char *bin, const char *hexstr, size_t len)
{
int nibble1, nibble2;
unsigned char idx;
bool ret = false;
while (*hexstr && len) {
if (!hexstr[1]) {
xprint_err("hex string truncated.\n");
return ret;
}
idx = *hexstr++;
nibble1 = hex2bin_tbl[idx];
idx = *hexstr++;
nibble2 = hex2bin_tbl[idx];
if ((nibble1<0) || (nibble2<0)) {
xprint_err("hex string scan failed.\n");
return ret;
}
*bin++ = (((unsigned char)nibble1)<<4) | ((unsigned char)nibble2);
--len;
}
if (len == 0 && *hexstr == 0) {
ret = true;
}
return ret;
}
void xreverse_byte(unsigned char *s, size_t n)
{
size_t i = 0;
size_t j = 0;
for (i=0, j=n-1; i len) ? len : n;
memcpy(value, a, n);
r = b - data;
}
else {
b = strstr(a, " ");
if (NULL == b) {
b = data + strlen(data);
}
n = b - a;
n = (n > len) ? len : n;
memcpy(value, a, n);
r = b - data;
}
}
else {
r = -1;
}
if (-1 == r) {
xprint_err("%s not find. pls check uri\n %s \n", key, data);
}
return r;
}
编译运行
ubuntu 14.04 gcc 5.5.0
[root@ubuntu:src]# gcc xmain.c xsha256.c xutils.c
[root@ubuntu:src]# ./a.out 0
{"data":{"height":0,"version":1,"mrkl_root":"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b","timestamp":1231006505,"bits":486604799,"nonce":2083236893,"hash":"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f","prev_block_hash":"0000000000000000000000000000000000000000000000000000000000000000","next_block_hash":"00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048","size":285,"pool_difficulty":2536,"difficulty":1,"tx_count":1,"reward_block":5000000000,"reward_fees":0,"created_at":1488909332,"confirmations":553612,"is_orphan":false,"curr_max_timestamp":1231006505,"is_sw_block":false,"stripped_size":285,"weight":1140,"extras":{"pool_name":"unknown","pool_link":""}},"err_no":0,"err_msg":null}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
block:0
version:1
prev_block_hash:0000000000000000000000000000000000000000000000000000000000000000
mrkl_root:3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a
timestamp:1231006505
bits:486604799
nonce:2083236893
hash:000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c
sha256-1=af42031e805ff493a07341e2f74ff58149d22ab9ba19f61343e2c86c71c5d66d
sha256-2=000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f