New blkmk_init_generation and blkmk_address_to_script functions to create a coinbase transaction if it isn't provided
This commit is contained in:
@@ -4,6 +4,7 @@ lib_LTLIBRARIES = \
|
||||
|
||||
|
||||
libblkmaker_@LIBBLKMAKER_API_VERSION@_la_SOURCES = \
|
||||
base58.c \
|
||||
blkmaker.c \
|
||||
blktemplate.c \
|
||||
hex.c
|
||||
|
||||
129
base58.c
Normal file
129
base58.c
Normal file
@@ -0,0 +1,129 @@
|
||||
#ifndef WIN32
|
||||
#include <arpa/inet.h>
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <blkmaker.h>
|
||||
|
||||
#include "private.h"
|
||||
|
||||
static const int8_t b58digits[] = {
|
||||
-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, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,
|
||||
-1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1,
|
||||
22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1,
|
||||
-1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46,
|
||||
47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
|
||||
};
|
||||
|
||||
bool _blkmk_b58tobin(void *bin, size_t binsz, const char *b58, size_t b58sz) {
|
||||
const unsigned char *b58u = (void*)b58;
|
||||
unsigned char *binu = bin;
|
||||
size_t outisz = (binsz + 3) / 4;
|
||||
uint32_t outi[outisz];
|
||||
uint64_t t;
|
||||
uint32_t c;
|
||||
size_t i, j;
|
||||
uint8_t bytesleft = binsz % 4;
|
||||
uint32_t zeromask = ~((1 << ((bytesleft) * 8)) - 1);
|
||||
|
||||
if (!b58sz)
|
||||
b58sz = strlen(b58);
|
||||
|
||||
memset(outi, 0, outisz * sizeof(*outi));
|
||||
|
||||
for (i = 0; i < b58sz; ++i)
|
||||
{
|
||||
if (b58u[i] & 0x80)
|
||||
// High-bit set on invalid digit
|
||||
return false;
|
||||
if (b58digits[b58u[i]] == -1)
|
||||
// Invalid base58 digit
|
||||
return false;
|
||||
c = b58digits[b58u[i]];
|
||||
for (j = outisz; j--; )
|
||||
{
|
||||
t = ((uint64_t)outi[j]) * 58 + c;
|
||||
c = (t & 0x3f00000000) >> 32;
|
||||
outi[j] = t & 0xffffffff;
|
||||
}
|
||||
if (c)
|
||||
// Output number too big (carry to the next int32)
|
||||
return false;
|
||||
if (outi[0] & zeromask)
|
||||
// Output number too big (last int32 filled too far)
|
||||
return false;
|
||||
}
|
||||
|
||||
j = 0;
|
||||
switch (bytesleft) {
|
||||
case 3:
|
||||
*(binu++) = (outi[0] & 0xff0000) >> 16;
|
||||
case 2:
|
||||
*(binu++) = (outi[0] & 0xff00) >> 8;
|
||||
case 1:
|
||||
*(binu++) = (outi[0] & 0xff);
|
||||
++j;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (; j < outisz; ++j)
|
||||
{
|
||||
*((uint32_t*)binu) = htonl(outi[j]);
|
||||
binu += sizeof(uint32_t);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int _blkmk_b58check(void *bin, size_t binsz) {
|
||||
unsigned char buf[32];
|
||||
unsigned char *binc = bin;
|
||||
if (!_blkmk_dblsha256(buf, bin, binsz - 4))
|
||||
return -2;
|
||||
if (memcmp(&binc[binsz - 4], buf, 4))
|
||||
return -1;
|
||||
return binc[0];
|
||||
}
|
||||
|
||||
size_t blkmk_address_to_script(void *out, size_t outsz, const char *addr) {
|
||||
unsigned char addrbin[25];
|
||||
unsigned char *cout = out;
|
||||
int addrver;
|
||||
size_t rv;
|
||||
|
||||
if (!_blkmk_b58tobin(addrbin, sizeof(addrbin), addr, 0))
|
||||
return 0;
|
||||
addrver = _blkmk_b58check(addrbin, sizeof(addrbin));
|
||||
switch (addrver) {
|
||||
case 0: // Bitcoin pubkey hash
|
||||
case 111: // Testnet pubkey hash
|
||||
if (outsz < (rv = 24))
|
||||
return rv;
|
||||
cout[ 0] = 0x76; // OP_DUP
|
||||
cout[ 1] = 0xa9; // OP_HASH160
|
||||
cout[ 2] = 0x14; // push 20 bytes
|
||||
memcpy(&cout[3], &addrbin[1], 20);
|
||||
cout[22] = 0x88; // OP_EQUALVERIFY
|
||||
cout[23] = 0xac; // OP_CHECKSIG
|
||||
return rv;
|
||||
case 5: // Bitcoin script hash
|
||||
case 196: // Testnet script hash
|
||||
if (outsz < (rv = 22))
|
||||
return rv;
|
||||
cout[ 0] = 0xa9; // OP_HASH160
|
||||
cout[ 1] = 0x14; // push 20 bytes
|
||||
memcpy(&cout[2], &addrbin[1], 20);
|
||||
cout[21] = 0x87; // OP_EQUAL
|
||||
return rv;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
49
blkmaker.c
49
blkmaker.c
@@ -1,5 +1,6 @@
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
@@ -8,6 +9,8 @@
|
||||
#include <blkmaker.h>
|
||||
#include <blktemplate.h>
|
||||
|
||||
#include "private.h"
|
||||
|
||||
static inline
|
||||
void my_htole32(unsigned char *buf, uint32_t n) {
|
||||
buf[0] = (n >> 0) % 256;
|
||||
@@ -16,6 +19,12 @@ void my_htole32(unsigned char *buf, uint32_t n) {
|
||||
buf[3] = (n >> 24) % 256;
|
||||
}
|
||||
|
||||
static inline
|
||||
void my_htole64(unsigned char *buf, uint64_t n) {
|
||||
for (int i = 0; i < 8; ++i)
|
||||
buf[i] = (n >> (8*i)) & 0xff;
|
||||
}
|
||||
|
||||
|
||||
bool (*blkmk_sha256_impl)(void *, const void *, size_t) = NULL;
|
||||
|
||||
@@ -25,6 +34,46 @@ bool _blkmk_dblsha256(void *hash, const void *data, size_t datasz) {
|
||||
|
||||
#define dblsha256 _blkmk_dblsha256
|
||||
|
||||
uint64_t blkmk_init_generation(blktemplate_t *tmpl, void *script, size_t scriptsz) {
|
||||
if (tmpl->cbtxn)
|
||||
return 0;
|
||||
|
||||
// Skip "no extranonce" scriptSig, since it would be too short (min 2 bytes)
|
||||
++tmpl->next_dataid;
|
||||
|
||||
size_t datasz = 60 + scriptsz;
|
||||
unsigned char *data = malloc(datasz);
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
memcpy(&data[0],
|
||||
"\x01\0\0\0" // txn ver
|
||||
"\x01" // input count
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" // prevout
|
||||
"\xff\xff\xff\xff" // index (-1)
|
||||
"\0" // scriptSig length (0; extranonce will bring up to 4)
|
||||
"\xff\xff\xff\xff" // sequence
|
||||
"\x01" // output count
|
||||
, 47);
|
||||
my_htole64(&data[47], tmpl->cbvalue);
|
||||
data[55] = scriptsz;
|
||||
memcpy(&data[56], script, scriptsz);
|
||||
memset(&data[56 + scriptsz], 0, 4); // lock time
|
||||
|
||||
struct blktxn_t *txn = calloc(1, sizeof(*tmpl->cbtxn));
|
||||
if (!tmpl->cbtxn)
|
||||
{
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
txn->data = data;
|
||||
txn->datasz = datasz;
|
||||
|
||||
tmpl->cbtxn = txn;
|
||||
return tmpl->cbvalue;
|
||||
}
|
||||
|
||||
static
|
||||
bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl, unsigned char *cbtxndata, size_t cbtxndatasz) {
|
||||
size_t hashcount = tmpl->txncount + 1;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define BLKMAKER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <blktemplate.h>
|
||||
|
||||
@@ -10,6 +11,7 @@
|
||||
|
||||
extern bool (*blkmk_sha256_impl)(void *hash_out, const void *data, size_t datasz);
|
||||
|
||||
extern uint64_t blkmk_init_generation(blktemplate_t *, void *script, size_t scriptsz);
|
||||
extern ssize_t blkmk_append_coinbase_safe(blktemplate_t *, const void *append, size_t appendsz);
|
||||
extern bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, size_t *offs);
|
||||
extern size_t blkmk_get_data(blktemplate_t *, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire, unsigned int *out_dataid);
|
||||
@@ -17,4 +19,6 @@ extern blktime_diff_t blkmk_time_left(const blktemplate_t *, time_t nowtime);
|
||||
extern unsigned long blkmk_work_left(const blktemplate_t *);
|
||||
#define BLKMK_UNLIMITED_WORK_COUNT ULONG_MAX
|
||||
|
||||
extern size_t blkmk_address_to_script(void *out, size_t outsz, const char *addr);
|
||||
|
||||
#endif
|
||||
|
||||
16
example.c
16
example.c
@@ -9,8 +9,22 @@
|
||||
#include <blkmaker.h>
|
||||
#include <blkmaker_jansson.h>
|
||||
|
||||
#include "private.h"
|
||||
#include "testinput.c"
|
||||
|
||||
void testb58() {
|
||||
char bufx[26] = {'\xff'};
|
||||
char *buf = &bufx[1];
|
||||
if (!_blkmk_b58tobin(buf, 25, "1Baf75Ferj6A7AoN565gCQj9kGWbDMHfN9", 0))
|
||||
exit(1);
|
||||
if (bufx[0] != '\xff')
|
||||
exit(2);
|
||||
char cbuf[51];
|
||||
_blkmk_bin2hex(cbuf, buf, 25);
|
||||
printf("Base58 raw data: %s\n", cbuf);
|
||||
printf("Base58 check: %d\n", _blkmk_b58check(buf, 25));
|
||||
}
|
||||
|
||||
static
|
||||
void send_json(json_t *req) {
|
||||
char *s = json_dumps(req, JSON_INDENT(2));
|
||||
@@ -32,6 +46,8 @@ int main(int argc, char**argv) {
|
||||
|
||||
blkmk_sha256_impl = my_sha256;
|
||||
|
||||
testb58();
|
||||
|
||||
tmpl = blktmpl_create();
|
||||
assert(tmpl);
|
||||
req = blktmpl_request_jansson(blktmpl_addcaps(tmpl), NULL);
|
||||
|
||||
@@ -11,4 +11,8 @@ extern bool _blkmk_dblsha256(void *hash, const void *data, size_t datasz);
|
||||
extern void _blkmk_bin2hex(char *out, const void *data, size_t datasz);
|
||||
extern bool _blkmk_hex2bin(void *o, const char *x, size_t len);
|
||||
|
||||
// base58.c
|
||||
extern bool _blkmk_b58tobin(void *bin, size_t binsz, const char *b58, size_t b58sz);
|
||||
extern int _blkmk_b58check(void *bin, size_t binsz);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user