<commit_before>/*
 * Copyright 2016 <NAME>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the standard MIT license.  See COPYING for more details.
 */

#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <gcrypt.h>

#include "blktemplate.h"
#include "blkmaker.h"
#include "blkmaker_jansson.h"

static bool my_sha256(void *digest, const void *buffer, size_t length) {
	gcry_md_hash_buffer(GCRY_MD_SHA256, digest, buffer, length);
	return true;
}

static void capabilityname_test() {
	for (unsigned int i = 0; i < GBT_CAPABILITY_COUNT; ++i) {
		const gbt_capabilities_t capid = (1 << i);
		const char * const capname = blktmpl_capabilityname(capid);
		if (!capname) {
			continue;
		}
		const size_t strlen_capname = strlen(capname);
		assert(strlen_capname > 0);
		assert(strlen_capname <= BLKTMPL_LONGEST_CAPABILITY_NAME);
		assert(blktmpl_getcapability(capname) == capid);
	}
}

static void blktxn_test(const int c) {
	struct blktxn_t * const txn = malloc(sizeof(*txn));
	memset(txn, c, sizeof(*txn));
	blktxn_init(txn);
	blktxn_clean(txn);
	free(txn);
}

static bool caps_includes(const uint32_t caps, const uint32_t expected_caps) {
	return (caps & expected_caps) == expected_caps;
}

static void blktmpl_test() {
	blktemplate_t * const tmpl = blktmpl_create();
	
	{
		static const uint32_t expected_fresh_caps = GBT_CBTXN | GBT_WORKID | BMM_TIMEINC | BMM_CBAPPEND | BMM_VERFORCE | BMM_VERDROP | BMAb_COINBASE | BMAb_TRUNCATE;
		assert(caps_includes(blktmpl_addcaps(tmpl), expected_fresh_caps));
	}
	
	assert(!tmpl->version);
	assert(!blktmpl_get_longpoll(tmpl));
	assert(!blktmpl_get_submitold(tmpl));
	
	blktmpl_free(tmpl);
}

static bool json_are_equal(json_t * const ja, json_t * const jb) {
	char *sa, *sb;
	sa = json_dumps(ja, JSON_COMPACT | JSON_SORT_KEYS);
	sb = json_dumps(jb, JSON_COMPACT | JSON_SORT_KEYS);
	const bool rv = !strcmp(sa, sb);
	free(sa);
	free(sb);
	return rv;
}

static void rulecompare(json_t * const jb, const char * const * const rulelist) {
	const size_t z = json_array_size(jb);
	const char *sa;
	json_t *jc;
	
	for (size_t i = 0; i < z; ++i) {
		assert((jc = json_array_get(jb, i)));
		assert((sa = json_string_value(jc)));
		assert(!strcmp(sa, rulelist[i]));
	}
	assert(!rulelist[z]);
}

static void check_request(json_t * const ja, const char * const * const rulelist, uint32_t * const out_caps) {
	const char *sa;
	json_t *jb, *jc;
	
	assert(json_object_get(ja, "id"));
	assert((jb = json_object_get(ja, "method")));
	assert((sa = json_string_value(jb)));
	assert(!strcmp(sa, "getblocktemplate"));
	assert((jb = json_object_get(ja, "params")));
	assert(json_is_array(jb));
	assert(json_array_size(jb) >= 1);
	jc = json_array_get(jb, 0);
	assert(json_is_object(jc));
	assert((jb = json_object_get(jc, "maxversion")));
	assert(json_number_value(jb) == BLKMAKER_MAX_BLOCK_VERSION);
	assert((jb = json_object_get(jc, "rules")));
	assert(json_is_array(jb));
	rulecompare(jb, rulelist);
	if (out_caps) {
		*out_caps = 0;
		if ((jb = json_object_get(jc, "capabilities")) && json_is_array(jb)) {
			const size_t z = json_array_size(jb);
			for (size_t i = 0; i < z; ++i) {
				assert((jc = json_array_get(jb, i)));
				assert((sa = json_string_value(jc)));
				uint32_t capid = blktmpl_getcapability(sa);
				assert(capid);
				*out_caps |= capid;
			}
		}
	}
}

static void blktmpl_request_jansson_test_old() {
	blktemplate_t * const tmpl = blktmpl_create();
	json_t *ja, *jb;
	
	ja = blktmpl_request_jansson2(0, NULL, blkmk_supported_rules);
	jb = blktmpl_request_jansson(0, NULL);
	assert(json_are_equal(ja, jb));
	json_decref(jb);
	
	check_request(ja, blkmk_supported_rules, NULL);
	
	json_decref(ja);
	blktmpl_free(tmpl);
}

static void blktmpl_request_jansson_test_custom_rulelist() {
	blktemplate_t * const tmpl = blktmpl_create();
	json_t *ja;
	const char *custom_rulelist[] = {
		"abc",
		"xyz",
		NULL
	};
	
	ja = blktmpl_request_jansson2(0, NULL, custom_rulelist);
	check_request(ja, custom_rulelist, NULL);
	
	json_decref(ja);
	blktmpl_free(tmpl);
}

static void blktmpl_request_jansson_test_custom_caps_i(json_t * const ja, const uint32_t test_caps) {
	uint32_t caps;
	check_request(ja, blkmk_supported_rules, &caps);
	assert(caps == test_caps);
	json_decref(ja);
}

static void blktmpl_request_jansson_test_custom_caps() {
	blktemplate_t * const tmpl = blktmpl_create();
	json_t *ja;
	uint32_t test_caps = GBT_SERVICE | GBT_LONGPOLL;
	
	ja = blktmpl_request_jansson2(test_caps, NULL, blkmk_supported_rules);
	blktmpl_request_jansson_test_custom_caps_i(ja, test_caps);
	
	test_caps |= blktmpl_addcaps(tmpl);
	ja = blktmpl_request_jansson2(test_caps, NULL, blkmk_supported_rules);
	blktmpl_request_jansson_test_custom_caps_i(ja, test_caps);
	
	blktmpl_free(tmpl);
}

static void blktmpl_request_jansson_test_longpoll() {
	blktemplate_t * const tmpl = blktmpl_create();
	static const char * const lpid = "mylpid00";
	const char *sa;
	json_t *ja, *jb, *jc;
	
	ja = blktmpl_request_jansson2(0, lpid, blkmk_supported_rules);
	check_request(ja, blkmk_supported_rules, NULL);
	
	jb = json_array_get(json_object_get(ja, "params"), 0);
	assert((jc = json_object_get(jb, "longpollid")));
	assert((sa = json_string_value(jc)));
	assert(!strcmp(sa, lpid));
	
	json_decref(ja);
	blktmpl_free(tmpl);
}

static const char *blktmpl_add_jansson_str(blktemplate_t * const tmpl, const char * const s, const time_t time_rcvd) {
	json_t * const j = json_loads(s, 0, NULL);
	assert(j);
	const char * const rv = blktmpl_add_jansson(tmpl, j, time_rcvd);
	json_decref(j);
	return rv;
}

static const time_t simple_time_rcvd = 0x777;

static void blktmpl_jansson_simple() {
	blktemplate_t * const tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd));
	assert(tmpl->version == 2);
	assert(tmpl->height == 3);
	assert(!memcmp(tmpl->diffbits, "\xff\xff\0\x1d", 4));
	assert(tmpl->curtime == 777);
	for (int i = 0; i < 7; ++i) {
		assert(tmpl->prevblk[i] == 0x77777777);
	}
	assert(!tmpl->prevblk[7]);
	assert(tmpl->cbvalue == 512);
	
	// Check clear values
	assert(tmpl->txncount == 0);
	assert(tmpl->txns_datasz == 0);
	assert(tmpl->txns_sigops == 0);
	assert(!tmpl->cbtxn);
	assert(!tmpl->workid);
	assert(!blktmpl_get_longpoll(tmpl));
	assert(blktmpl_get_submitold(tmpl));
	assert(!tmpl->target);
	assert(!tmpl->mutations);
	assert(tmpl->aux_count == 0);
	assert(!tmpl->rules);
	assert(!tmpl->unsupported_rule);
	assert(!tmpl->vbavailable);
	assert(!tmpl->vbrequired);
	
	// Check reasonable default ranges
	assert(tmpl->sigoplimit >= 20000);
	assert(tmpl->sizelimit >= 1000000);
	assert(tmpl->expires >= 60);
	assert(tmpl->maxtime >= tmpl->curtime + 60);
	assert(tmpl->maxtimeoff >= 60);
	assert(tmpl->mintime <= tmpl->curtime - 60);
	assert(tmpl->mintimeoff <= -60);
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_bip22_required() {
	blktemplate_t * const tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\"}", simple_time_rcvd));
	assert(tmpl->version == 3);
	assert(tmpl->height == 4);
	assert(!memcmp(tmpl->diffbits, "\xff\x7f\0\x1d", 4));
	assert(tmpl->curtime == 877);
	for (int i = 0; i < 7; ++i) {
		assert(tmpl->prevblk[i] == 0xa7777777);
	}
	assert(!tmpl->prevblk[7]);
	assert(tmpl->cbvalue == 640);
	assert(tmpl->sigoplimit == 100);
	assert(tmpl->sizelimit == 1000);
	assert(tmpl->txncount == 3);
	assert(tmpl->txns);
	assert(tmpl->txns[0].data);
	assert(tmpl->txns[0].datasz == 57);
	assert(!memcmp(tmpl->txns[0].data, "\x01\0\0\0\x01\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xaa\xaa\xaa\xaa\0\x22\x22\x22\x22\x01\0\x10\0\0\x01\x51\0\0\0\0", 57));
	assert(tmpl->txns[0].dependscount == -1);
	assert(tmpl->txns[0].fee_ == -1);
	assert(tmpl->txns[0].required);
	assert(tmpl->txns[0].sigops_ == -1);
	assert(tmpl->txns[1].data);
	assert(tmpl->txns[1].datasz == 57);
	assert(!memcmp(tmpl->txns[1].data, "\x01\0\0\0\x01\x1c\x69\xf2\x12\xe6\x2f\x2c\xdd\x80\x93\x7c\x9c\x08\x57\xce\xde\xc0\x05\xb1\x1d\x3b\x90\x2d\x21\0\x7c\x93\x2c\x1c\x7c\xd2\x0f\0\0\0\0\0\x44\x44\x44\x44\x01\0\x10\0\0\x01\x51\0\0\0\0", 57));
	assert(tmpl->txns[1].dependscount == 1);
	assert(tmpl->txns[1].depends);
	assert(tmpl->txns[1].depends[0] == 1);
	assert(tmpl->txns[1].fee_ == 12);
	assert(!tmpl->txns[1].required);
	assert(tmpl->txns[1].sigops_ == 4);
	assert(!memcmp(tmpl->txns[1].hash_, "\x8d\x7e\x01\x67\x43\x9d\xab\x18\x6e\x86\xf9\x13\xb2\x7f\x3a\xc2\x15\x67\xdd\x4e\xde\xf8\x9a\xa8\x01\x64\x99\x67\x8b\x1a\xda\x8e", 32));
	assert(tmpl->txns[2].data);
	assert(tmpl->txns[2].datasz == 57);
	assert(!memcmp(tmpl->txns[2].data, "\x01\0\0\0\x01\0\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xaa\xaa\xaa\xaa\0\x55\x55\x55\x55\x01\0\x10\0\0\x01\x51\0\0\0\0", 57));
	assert(tmpl->txns[2].dependscount == -1);
	assert(tmpl->txns[2].fee_ == -1);
	assert(!tmpl->txns[2].required);
	assert(tmpl->txns[2].sigops_ == -1);
	assert(tmpl->cbtxn->data);
	assert(tmpl->cbtxn->datasz == 64);
	assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\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\xff\xff\xff\xff\x07\x01\x04\x04\xde\xad\xbe\xef\x33\x33\x33\x33\x01\0\x10\0\0\x01\x51\0\0\0\0", 64));
	assert(tmpl->aux_count == 1);
	assert(tmpl->auxs);
	assert(tmpl->auxs[0].auxname);
	assert(!strcmp(tmpl->auxs[0].auxname, "dummy"));
	assert(tmpl->auxs[0].datasz == 4);
	assert(!memcmp(tmpl->auxs[0].data, "\xde\xad\xbe\xef", 4));
	assert(tmpl->workid);
	assert(!strcmp(tmpl->workid, "mywork"));
	assert(blktmpl_get_submitold(tmpl));
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_bip22_longpoll() {
	blktemplate_t *tmpl = blktmpl_create();
	const struct blktmpl_longpoll_req *lp;
	
	assert(!blktmpl_get_longpoll(tmpl));
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"longpollid\":\"mylpid\"}", simple_time_rcvd));
	lp = blktmpl_get_longpoll(tmpl);
	assert(lp->id);
	assert(!strcmp(lp->id, "mylpid"));
	assert(!lp->uri);
	assert(blktmpl_get_submitold(tmpl));
	
	blktmpl_free(tmpl);
	tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"longpollid\":\"myLPid\",\"longpolluri\":\"/LP\",\"submitold\":false}", simple_time_rcvd));
	lp = blktmpl_get_longpoll(tmpl);
	assert(lp->id);
	assert(!strcmp(lp->id, "myLPid"));
	assert(lp->uri);
	assert(!strcmp(lp->uri, "/LP"));
	assert(!blktmpl_get_submitold(tmpl));
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_bip23_bpe() {
	blktemplate_t *tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"expires\":99,\"target\":\"0000000077777777777777777777777777777777777777777777777777777777\"}", simple_time_rcvd));
	assert(tmpl->expires == 99);
	assert(!(*tmpl->target)[0]);
	for (int i = 1; i < 8; ++i) {
		assert((*tmpl->target)[i] == 0x77777777);
	}
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_bip23_mutations() {
	blktemplate_t *tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"maxtime\":2113929216,\"maxtimeoff\":50,\"mintime\":800,\"mintimeoff\":-50,\"mutable\":[\"prevblock\",\"version/force\"],\"noncerange\":\"01000000f0000000\"}", simple_time_rcvd));
	assert(tmpl->maxtime == 2113929216);
	assert(tmpl->maxtimeoff == 50);
	assert(tmpl->mintime == 800);
	assert(tmpl->mintimeoff == -50);
	// As of right now, implied mutations are not included in the value
	// assert(tmpl->mutations == (BMM_CBAPPEND | BMM_CBSET | BMM_GENERATE | BMM_TIMEINC | BMM_TIMEDEC | BMM_TXNADD | BMM_PREVBLK | BMM_VERFORCE));
	assert(caps_includes(tmpl->mutations, BMM_PREVBLK | BMM_VERFORCE));
	
	blktmpl_free(tmpl);
	tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"mutable\":[\"version/reduce\",\"coinbase/append\",\"generation\",\"time\",\"transactions\"],\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"transactions\":[]}", simple_time_rcvd));
	assert(tmpl->mutations == (BMM_CBAPPEND | BMM_GENERATE | BMM_TIMEINC | BMM_TIMEDEC | BMM_TXNADD | BMM_VERDROP));
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_bip23_abbrev() {
	blktemplate_t * const tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"mutable\":[\"submit/hash\",\"submit/coinbase\",\"submit/truncate\"]}", simple_time_rcvd));
	assert(tmpl->mutations == (BMA_TXNHASH | BMAb_COINBASE | BMAb_TRUNCATE));
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_bip9() {
	blktemplate_t *tmpl;
	
	tmpl = blktmpl_create();
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\"],\"vbavailable\":{\"!segwit\":7}}", simple_time_rcvd));
	assert(tmpl->version == 0x20000080);
	assert(tmpl->rules);
	assert(tmpl->rules[0]);
	assert(!strcmp(tmpl->rules[0], "csv"));
	assert(!tmpl->rules[1]);
	assert(!tmpl->unsupported_rule);
	assert(tmpl->vbavailable);
	assert(tmpl->vbavailable[0]);
	assert(tmpl->vbavailable[0]->name);
	assert(!strcmp(tmpl->vbavailable[0]->name, "!segwit"));
	assert(tmpl->vbavailable[0]->bitnum == 7);
	assert(!tmpl->vbavailable[1]);
	assert(!tmpl->vbrequired);
	
	blktmpl_free(tmpl);
	tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\"],\"vbavailable\":{\"!segwit\":7},\"vbrequired\":128}", simple_time_rcvd));
	assert(tmpl->version == 0x20000080);
	assert(tmpl->rules);
	assert(tmpl->rules[0]);
	assert(!strcmp(tmpl->rules[0], "csv"));
	assert(!tmpl->rules[1]);
	assert(!tmpl->unsupported_rule);
	assert(tmpl->vbavailable);
	assert(tmpl->vbavailable[0]);
	assert(tmpl->vbavailable[0]->name);
	assert(!strcmp(tmpl->vbavailable[0]->name, "!segwit"));
	assert(tmpl->vbavailable[0]->bitnum == 7);
	assert(!tmpl->vbavailable[1]);
	assert(tmpl->vbrequired == 0x80);
	
	blktmpl_free(tmpl);
	tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\",\"foo\"],\"vbavailable\":{}}", simple_time_rcvd));
	assert(tmpl->version == 0x20000080);
	assert(tmpl->rules);
	assert(tmpl->rules[0]);
	assert(!strcmp(tmpl->rules[0], "csv"));
	assert(tmpl->rules[1]);
	assert(!strcmp(tmpl->rules[1], "foo"));
	assert(!tmpl->rules[2]);
	assert(tmpl->unsupported_rule);
	assert(tmpl->vbavailable);
	assert(!tmpl->vbavailable[0]);
	assert(!tmpl->vbrequired);
	
	blktmpl_free(tmpl);
	tmpl = blktmpl_create();
	
	assert(blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\",\"!foo\"],\"vbavailable\":{}}", simple_time_rcvd));
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_submit_data_check(const char * const sa, const int level) {
	assert(strlen(sa) >= 160);
	assert(!memcmp(sa, "03000000777777a7777777a7777777a7777777a7777777a7777777a7777777a700000000", 72));
	// Don't check merkle root
	assert(!memcmp(&sa[136], "6d030000ff7f001d", 16));
	// Don't check nonce
	size_t pos = 160;
	if (level > 0) {
		assert(!strncmp(&sa[pos], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000", 130));
		pos += 130;
		if (level > 1) {
			assert(!strcmp(&sa[pos], "01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa0022222222010010000001510000000001000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f000000000044444444010010000001510000000001000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000"));
			pos += strlen(&sa[pos]);
		}
	}
	if (level >= 0) {
		assert(sa[pos] == '\0');
	}
}

static void blktmpl_jansson_propose_check(json_t *j, const int level) {
	const char *sa;
	
	j = json_array_get(json_object_get(j, "params"), 0);
	assert((j = json_object_get(j, "data")));
	assert((sa = json_string_value(j)));
	return blktmpl_jansson_submit_data_check(sa, level);
}

static void blktmpl_jansson_propose() {
	blktemplate_t * const tmpl = blktmpl_create();
	const char *sa;
	json_t *j, *ja, *jb;
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\"}", simple_time_rcvd));
	
	assert((j = blktmpl_propose_jansson(tmpl, 0, false)));
	check_request(j, blkmk_supported_rules, NULL);
	
	ja = json_array_get(json_object_get(j, "params"), 0);
	assert((jb = json_object_get(ja, "mode")));
	assert((sa = json_string_value(jb)));
	assert(!strcmp(sa, "proposal"));
	assert((jb = json_object_get(ja, "workid")));
	assert((sa = json_string_value(jb)));
	assert(!strcmp(sa, "mywork"));
	blktmpl_jansson_propose_check(j, 2);
	json_decref(j);
	
	tmpl->mutations |= BMAb_COINBASE;
	assert((j = blktmpl_propose_jansson(tmpl, 0, false)));
	check_request(j, blkmk_supported_rules, NULL);
	blktmpl_jansson_propose_check(j, 1);
	json_decref(j);
	
	tmpl->mutations |= BMAb_TRUNCATE;
	assert((j = blktmpl_propose_jansson(tmpl, 0, false)));
	check_request(j, blkmk_supported_rules, NULL);
	blktmpl_jansson_propose_check(j, 0);
	json_decref(j);
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_submit() {
	blktemplate_t * const tmpl = blktmpl_create();
	const char *sa;
	uint8_t data[76];
	int16_t i16;
	unsigned int dataid;
	json_t *j, *ja, *jb, *jc;
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\",\"mutable\":[\"submit/coinbase\",\"submit/truncate\",\"coinbase/append\"]}", simple_time_rcvd));
	
	assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid));
	
	assert((j = blkmk_submit_foreign_jansson(tmpl, data, 0, 0x12345678)));
	assert((ja = json_object_get(j, "params")));
	assert(json_is_array(ja));
	assert(json_array_size(ja) >= 1);
	assert((sa = json_string_value(json_array_get(ja, 0))));
	blktmpl_jansson_submit_data_check(sa, 2);
	if (json_array_size(ja) >= 2) {
		assert(json_is_object((jb = json_array_get(ja, 1))));
		assert(!json_object_get(jb, "workid"));
	}
	json_decref(j);
	
	assert((j = blkmk_submit_jansson(tmpl, data, 0, 0x12345678)));
	assert(json_object_get(j, "id"));
	assert((ja = json_object_get(j, "method")));
	assert((sa = json_string_value(ja)));
	assert(!strcmp(sa, "submitblock"));
	assert((ja = json_object_get(j, "params")));
	assert(json_is_array(ja));
	assert(json_array_size(ja) >= 2);
	assert((sa = json_string_value(json_array_get(ja, 0))));
	blktmpl_jansson_submit_data_check(sa, 0);
	assert(!memcmp(&sa[72], "512a63f45f96f0269a2d23ccd96bcf0322ee4f60254748e30b89e2b59431aba16d030000ff7f001d12345678", 64));  // merkle root
	assert(!memcmp(&sa[152], "12345678", 8));  // nonce
	assert(json_is_object((jb = json_array_get(ja, 1))));
	assert((jc = json_object_get(jb, "workid")));
	assert((sa = json_string_value(jc)));
	assert(!strcmp(sa, "mywork"));
	json_decref(j);
	
	assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid));
	
	assert((j = blkmk_submit_jansson(tmpl, data, dataid, 0x12345678)));
	assert((ja = json_object_get(j, "params")));
	assert(json_is_array(ja));
	assert(json_array_size(ja) >= 2);
	assert((sa = json_string_value(json_array_get(ja, 0))));
	blktmpl_jansson_submit_data_check(sa, -1);
	// TODO: Check inserted dataid
	assert(json_is_object((jb = json_array_get(ja, 1))));
	assert((jc = json_object_get(jb, "workid")));
	assert((sa = json_string_value(jc)));
	assert(!strcmp(sa, "mywork"));
	json_decref(j);
	
	blktmpl_free(tmpl);
}

int main() {
	blkmk_sha256_impl = my_sha256;
	
	puts("capabilityname");
	capabilityname_test();
	
	puts("blktxn");
	blktxn_test('\0');
	blktxn_test('\xa5');
	blktxn_test('\xff');
	
	puts("blktmpl");
	blktmpl_test();
	
	puts("blktmpl_request_jansson");
	blktmpl_request_jansson_test_old();
	blktmpl_request_jansson_test_custom_rulelist();
	blktmpl_request_jansson_test_custom_caps();
	blktmpl_request_jansson_test_longpoll();
	
	puts("blktmpl_jansson");
	blktmpl_jansson_simple();
	blktmpl_jansson_bip22_required();
	blktmpl_jansson_bip22_longpoll();
	blktmpl_jansson_bip23_bpe();
	blktmpl_jansson_bip23_mutations();
	blktmpl_jansson_bip23_abbrev();
	blktmpl_jansson_bip9();
	blktmpl_jansson_propose();
	blktmpl_jansson_submit();
}<commit_msg>test: Check out mdata submissions<commit_after>/*
 * Copyright 2016 <NAME>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the standard MIT license.  See COPYING for more details.
 */

#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <gcrypt.h>

#include "blktemplate.h"
#include "blkmaker.h"
#include "blkmaker_jansson.h"

static bool my_sha256(void *digest, const void *buffer, size_t length) {
	gcry_md_hash_buffer(GCRY_MD_SHA256, digest, buffer, length);
	return true;
}

static void capabilityname_test() {
	for (unsigned int i = 0; i < GBT_CAPABILITY_COUNT; ++i) {
		const gbt_capabilities_t capid = (1 << i);
		const char * const capname = blktmpl_capabilityname(capid);
		if (!capname) {
			continue;
		}
		const size_t strlen_capname = strlen(capname);
		assert(strlen_capname > 0);
		assert(strlen_capname <= BLKTMPL_LONGEST_CAPABILITY_NAME);
		assert(blktmpl_getcapability(capname) == capid);
	}
}

static void blktxn_test(const int c) {
	struct blktxn_t * const txn = malloc(sizeof(*txn));
	memset(txn, c, sizeof(*txn));
	blktxn_init(txn);
	blktxn_clean(txn);
	free(txn);
}

static bool caps_includes(const uint32_t caps, const uint32_t expected_caps) {
	return (caps & expected_caps) == expected_caps;
}

static void blktmpl_test() {
	blktemplate_t * const tmpl = blktmpl_create();
	
	{
		static const uint32_t expected_fresh_caps = GBT_CBTXN | GBT_WORKID | BMM_TIMEINC | BMM_CBAPPEND | BMM_VERFORCE | BMM_VERDROP | BMAb_COINBASE | BMAb_TRUNCATE;
		assert(caps_includes(blktmpl_addcaps(tmpl), expected_fresh_caps));
	}
	
	assert(!tmpl->version);
	assert(!blktmpl_get_longpoll(tmpl));
	assert(!blktmpl_get_submitold(tmpl));
	
	blktmpl_free(tmpl);
}

static bool json_are_equal(json_t * const ja, json_t * const jb) {
	char *sa, *sb;
	sa = json_dumps(ja, JSON_COMPACT | JSON_SORT_KEYS);
	sb = json_dumps(jb, JSON_COMPACT | JSON_SORT_KEYS);
	const bool rv = !strcmp(sa, sb);
	free(sa);
	free(sb);
	return rv;
}

static void rulecompare(json_t * const jb, const char * const * const rulelist) {
	const size_t z = json_array_size(jb);
	const char *sa;
	json_t *jc;
	
	for (size_t i = 0; i < z; ++i) {
		assert((jc = json_array_get(jb, i)));
		assert((sa = json_string_value(jc)));
		assert(!strcmp(sa, rulelist[i]));
	}
	assert(!rulelist[z]);
}

static void check_request(json_t * const ja, const char * const * const rulelist, uint32_t * const out_caps) {
	const char *sa;
	json_t *jb, *jc;
	
	assert(json_object_get(ja, "id"));
	assert((jb = json_object_get(ja, "method")));
	assert((sa = json_string_value(jb)));
	assert(!strcmp(sa, "getblocktemplate"));
	assert((jb = json_object_get(ja, "params")));
	assert(json_is_array(jb));
	assert(json_array_size(jb) >= 1);
	jc = json_array_get(jb, 0);
	assert(json_is_object(jc));
	assert((jb = json_object_get(jc, "maxversion")));
	assert(json_number_value(jb) == BLKMAKER_MAX_BLOCK_VERSION);
	assert((jb = json_object_get(jc, "rules")));
	assert(json_is_array(jb));
	rulecompare(jb, rulelist);
	if (out_caps) {
		*out_caps = 0;
		if ((jb = json_object_get(jc, "capabilities")) && json_is_array(jb)) {
			const size_t z = json_array_size(jb);
			for (size_t i = 0; i < z; ++i) {
				assert((jc = json_array_get(jb, i)));
				assert((sa = json_string_value(jc)));
				uint32_t capid = blktmpl_getcapability(sa);
				assert(capid);
				*out_caps |= capid;
			}
		}
	}
}

static void blktmpl_request_jansson_test_old() {
	blktemplate_t * const tmpl = blktmpl_create();
	json_t *ja, *jb;
	
	ja = blktmpl_request_jansson2(0, NULL, blkmk_supported_rules);
	jb = blktmpl_request_jansson(0, NULL);
	assert(json_are_equal(ja, jb));
	json_decref(jb);
	
	check_request(ja, blkmk_supported_rules, NULL);
	
	json_decref(ja);
	blktmpl_free(tmpl);
}

static void blktmpl_request_jansson_test_custom_rulelist() {
	blktemplate_t * const tmpl = blktmpl_create();
	json_t *ja;
	const char *custom_rulelist[] = {
		"abc",
		"xyz",
		NULL
	};
	
	ja = blktmpl_request_jansson2(0, NULL, custom_rulelist);
	check_request(ja, custom_rulelist, NULL);
	
	json_decref(ja);
	blktmpl_free(tmpl);
}

static void blktmpl_request_jansson_test_custom_caps_i(json_t * const ja, const uint32_t test_caps) {
	uint32_t caps;
	check_request(ja, blkmk_supported_rules, &caps);
	assert(caps == test_caps);
	json_decref(ja);
}

static void blktmpl_request_jansson_test_custom_caps() {
	blktemplate_t * const tmpl = blktmpl_create();
	json_t *ja;
	uint32_t test_caps = GBT_SERVICE | GBT_LONGPOLL;
	
	ja = blktmpl_request_jansson2(test_caps, NULL, blkmk_supported_rules);
	blktmpl_request_jansson_test_custom_caps_i(ja, test_caps);
	
	test_caps |= blktmpl_addcaps(tmpl);
	ja = blktmpl_request_jansson2(test_caps, NULL, blkmk_supported_rules);
	blktmpl_request_jansson_test_custom_caps_i(ja, test_caps);
	
	blktmpl_free(tmpl);
}

static void blktmpl_request_jansson_test_longpoll() {
	blktemplate_t * const tmpl = blktmpl_create();
	static const char * const lpid = "mylpid00";
	const char *sa;
	json_t *ja, *jb, *jc;
	
	ja = blktmpl_request_jansson2(0, lpid, blkmk_supported_rules);
	check_request(ja, blkmk_supported_rules, NULL);
	
	jb = json_array_get(json_object_get(ja, "params"), 0);
	assert((jc = json_object_get(jb, "longpollid")));
	assert((sa = json_string_value(jc)));
	assert(!strcmp(sa, lpid));
	
	json_decref(ja);
	blktmpl_free(tmpl);
}

static const char *blktmpl_add_jansson_str(blktemplate_t * const tmpl, const char * const s, const time_t time_rcvd) {
	json_t * const j = json_loads(s, 0, NULL);
	assert(j);
	const char * const rv = blktmpl_add_jansson(tmpl, j, time_rcvd);
	json_decref(j);
	return rv;
}

static const time_t simple_time_rcvd = 0x777;

static void blktmpl_jansson_simple() {
	blktemplate_t * const tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd));
	assert(tmpl->version == 2);
	assert(tmpl->height == 3);
	assert(!memcmp(tmpl->diffbits, "\xff\xff\0\x1d", 4));
	assert(tmpl->curtime == 777);
	for (int i = 0; i < 7; ++i) {
		assert(tmpl->prevblk[i] == 0x77777777);
	}
	assert(!tmpl->prevblk[7]);
	assert(tmpl->cbvalue == 512);
	
	// Check clear values
	assert(tmpl->txncount == 0);
	assert(tmpl->txns_datasz == 0);
	assert(tmpl->txns_sigops == 0);
	assert(!tmpl->cbtxn);
	assert(!tmpl->workid);
	assert(!blktmpl_get_longpoll(tmpl));
	assert(blktmpl_get_submitold(tmpl));
	assert(!tmpl->target);
	assert(!tmpl->mutations);
	assert(tmpl->aux_count == 0);
	assert(!tmpl->rules);
	assert(!tmpl->unsupported_rule);
	assert(!tmpl->vbavailable);
	assert(!tmpl->vbrequired);
	
	// Check reasonable default ranges
	assert(tmpl->sigoplimit >= 20000);
	assert(tmpl->sizelimit >= 1000000);
	assert(tmpl->expires >= 60);
	assert(tmpl->maxtime >= tmpl->curtime + 60);
	assert(tmpl->maxtimeoff >= 60);
	assert(tmpl->mintime <= tmpl->curtime - 60);
	assert(tmpl->mintimeoff <= -60);
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_bip22_required() {
	blktemplate_t * const tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\"}", simple_time_rcvd));
	assert(tmpl->version == 3);
	assert(tmpl->height == 4);
	assert(!memcmp(tmpl->diffbits, "\xff\x7f\0\x1d", 4));
	assert(tmpl->curtime == 877);
	for (int i = 0; i < 7; ++i) {
		assert(tmpl->prevblk[i] == 0xa7777777);
	}
	assert(!tmpl->prevblk[7]);
	assert(tmpl->cbvalue == 640);
	assert(tmpl->sigoplimit == 100);
	assert(tmpl->sizelimit == 1000);
	assert(tmpl->txncount == 3);
	assert(tmpl->txns);
	assert(tmpl->txns[0].data);
	assert(tmpl->txns[0].datasz == 57);
	assert(!memcmp(tmpl->txns[0].data, "\x01\0\0\0\x01\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xaa\xaa\xaa\xaa\0\x22\x22\x22\x22\x01\0\x10\0\0\x01\x51\0\0\0\0", 57));
	assert(tmpl->txns[0].dependscount == -1);
	assert(tmpl->txns[0].fee_ == -1);
	assert(tmpl->txns[0].required);
	assert(tmpl->txns[0].sigops_ == -1);
	assert(tmpl->txns[1].data);
	assert(tmpl->txns[1].datasz == 57);
	assert(!memcmp(tmpl->txns[1].data, "\x01\0\0\0\x01\x1c\x69\xf2\x12\xe6\x2f\x2c\xdd\x80\x93\x7c\x9c\x08\x57\xce\xde\xc0\x05\xb1\x1d\x3b\x90\x2d\x21\0\x7c\x93\x2c\x1c\x7c\xd2\x0f\0\0\0\0\0\x44\x44\x44\x44\x01\0\x10\0\0\x01\x51\0\0\0\0", 57));
	assert(tmpl->txns[1].dependscount == 1);
	assert(tmpl->txns[1].depends);
	assert(tmpl->txns[1].depends[0] == 1);
	assert(tmpl->txns[1].fee_ == 12);
	assert(!tmpl->txns[1].required);
	assert(tmpl->txns[1].sigops_ == 4);
	assert(!memcmp(tmpl->txns[1].hash_, "\x8d\x7e\x01\x67\x43\x9d\xab\x18\x6e\x86\xf9\x13\xb2\x7f\x3a\xc2\x15\x67\xdd\x4e\xde\xf8\x9a\xa8\x01\x64\x99\x67\x8b\x1a\xda\x8e", 32));
	assert(tmpl->txns[2].data);
	assert(tmpl->txns[2].datasz == 57);
	assert(!memcmp(tmpl->txns[2].data, "\x01\0\0\0\x01\0\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xaa\xaa\xaa\xaa\0\x55\x55\x55\x55\x01\0\x10\0\0\x01\x51\0\0\0\0", 57));
	assert(tmpl->txns[2].dependscount == -1);
	assert(tmpl->txns[2].fee_ == -1);
	assert(!tmpl->txns[2].required);
	assert(tmpl->txns[2].sigops_ == -1);
	assert(tmpl->cbtxn->data);
	assert(tmpl->cbtxn->datasz == 64);
	assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\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\xff\xff\xff\xff\x07\x01\x04\x04\xde\xad\xbe\xef\x33\x33\x33\x33\x01\0\x10\0\0\x01\x51\0\0\0\0", 64));
	assert(tmpl->aux_count == 1);
	assert(tmpl->auxs);
	assert(tmpl->auxs[0].auxname);
	assert(!strcmp(tmpl->auxs[0].auxname, "dummy"));
	assert(tmpl->auxs[0].datasz == 4);
	assert(!memcmp(tmpl->auxs[0].data, "\xde\xad\xbe\xef", 4));
	assert(tmpl->workid);
	assert(!strcmp(tmpl->workid, "mywork"));
	assert(blktmpl_get_submitold(tmpl));
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_bip22_longpoll() {
	blktemplate_t *tmpl = blktmpl_create();
	const struct blktmpl_longpoll_req *lp;
	
	assert(!blktmpl_get_longpoll(tmpl));
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"longpollid\":\"mylpid\"}", simple_time_rcvd));
	lp = blktmpl_get_longpoll(tmpl);
	assert(lp->id);
	assert(!strcmp(lp->id, "mylpid"));
	assert(!lp->uri);
	assert(blktmpl_get_submitold(tmpl));
	
	blktmpl_free(tmpl);
	tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"longpollid\":\"myLPid\",\"longpolluri\":\"/LP\",\"submitold\":false}", simple_time_rcvd));
	lp = blktmpl_get_longpoll(tmpl);
	assert(lp->id);
	assert(!strcmp(lp->id, "myLPid"));
	assert(lp->uri);
	assert(!strcmp(lp->uri, "/LP"));
	assert(!blktmpl_get_submitold(tmpl));
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_bip23_bpe() {
	blktemplate_t *tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"expires\":99,\"target\":\"0000000077777777777777777777777777777777777777777777777777777777\"}", simple_time_rcvd));
	assert(tmpl->expires == 99);
	assert(!(*tmpl->target)[0]);
	for (int i = 1; i < 8; ++i) {
		assert((*tmpl->target)[i] == 0x77777777);
	}
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_bip23_mutations() {
	blktemplate_t *tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"maxtime\":2113929216,\"maxtimeoff\":50,\"mintime\":800,\"mintimeoff\":-50,\"mutable\":[\"prevblock\",\"version/force\"],\"noncerange\":\"01000000f0000000\"}", simple_time_rcvd));
	assert(tmpl->maxtime == 2113929216);
	assert(tmpl->maxtimeoff == 50);
	assert(tmpl->mintime == 800);
	assert(tmpl->mintimeoff == -50);
	// As of right now, implied mutations are not included in the value
	// assert(tmpl->mutations == (BMM_CBAPPEND | BMM_CBSET | BMM_GENERATE | BMM_TIMEINC | BMM_TIMEDEC | BMM_TXNADD | BMM_PREVBLK | BMM_VERFORCE));
	assert(caps_includes(tmpl->mutations, BMM_PREVBLK | BMM_VERFORCE));
	
	blktmpl_free(tmpl);
	tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"mutable\":[\"version/reduce\",\"coinbase/append\",\"generation\",\"time\",\"transactions\"],\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"transactions\":[]}", simple_time_rcvd));
	assert(tmpl->mutations == (BMM_CBAPPEND | BMM_GENERATE | BMM_TIMEINC | BMM_TIMEDEC | BMM_TXNADD | BMM_VERDROP));
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_bip23_abbrev() {
	blktemplate_t * const tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"mutable\":[\"submit/hash\",\"submit/coinbase\",\"submit/truncate\"]}", simple_time_rcvd));
	assert(tmpl->mutations == (BMA_TXNHASH | BMAb_COINBASE | BMAb_TRUNCATE));
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_bip9() {
	blktemplate_t *tmpl;
	
	tmpl = blktmpl_create();
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\"],\"vbavailable\":{\"!segwit\":7}}", simple_time_rcvd));
	assert(tmpl->version == 0x20000080);
	assert(tmpl->rules);
	assert(tmpl->rules[0]);
	assert(!strcmp(tmpl->rules[0], "csv"));
	assert(!tmpl->rules[1]);
	assert(!tmpl->unsupported_rule);
	assert(tmpl->vbavailable);
	assert(tmpl->vbavailable[0]);
	assert(tmpl->vbavailable[0]->name);
	assert(!strcmp(tmpl->vbavailable[0]->name, "!segwit"));
	assert(tmpl->vbavailable[0]->bitnum == 7);
	assert(!tmpl->vbavailable[1]);
	assert(!tmpl->vbrequired);
	
	blktmpl_free(tmpl);
	tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\"],\"vbavailable\":{\"!segwit\":7},\"vbrequired\":128}", simple_time_rcvd));
	assert(tmpl->version == 0x20000080);
	assert(tmpl->rules);
	assert(tmpl->rules[0]);
	assert(!strcmp(tmpl->rules[0], "csv"));
	assert(!tmpl->rules[1]);
	assert(!tmpl->unsupported_rule);
	assert(tmpl->vbavailable);
	assert(tmpl->vbavailable[0]);
	assert(tmpl->vbavailable[0]->name);
	assert(!strcmp(tmpl->vbavailable[0]->name, "!segwit"));
	assert(tmpl->vbavailable[0]->bitnum == 7);
	assert(!tmpl->vbavailable[1]);
	assert(tmpl->vbrequired == 0x80);
	
	blktmpl_free(tmpl);
	tmpl = blktmpl_create();
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\",\"foo\"],\"vbavailable\":{}}", simple_time_rcvd));
	assert(tmpl->version == 0x20000080);
	assert(tmpl->rules);
	assert(tmpl->rules[0]);
	assert(!strcmp(tmpl->rules[0], "csv"));
	assert(tmpl->rules[1]);
	assert(!strcmp(tmpl->rules[1], "foo"));
	assert(!tmpl->rules[2]);
	assert(tmpl->unsupported_rule);
	assert(tmpl->vbavailable);
	assert(!tmpl->vbavailable[0]);
	assert(!tmpl->vbrequired);
	
	blktmpl_free(tmpl);
	tmpl = blktmpl_create();
	
	assert(blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\",\"!foo\"],\"vbavailable\":{}}", simple_time_rcvd));
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_submit_data_check(const char * const sa, const int level) {
	assert(strlen(sa) >= 160);
	assert(!memcmp(sa, "03000000777777a7777777a7777777a7777777a7777777a7777777a7777777a700000000", 72));
	// Don't check merkle root
	assert(!memcmp(&sa[136], "6d030000ff7f001d", 16));
	// Don't check nonce
	size_t pos = 160;
	if (level > 0) {
		assert(!strncmp(&sa[pos], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000", 130));
		pos += 130;
		if (level > 1) {
			assert(!strcmp(&sa[pos], "01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa0022222222010010000001510000000001000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f000000000044444444010010000001510000000001000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000"));
			pos += strlen(&sa[pos]);
		}
	}
	if (level >= 0) {
		assert(sa[pos] == '\0');
	}
}

static void blktmpl_jansson_propose_check(json_t *j, const int level) {
	const char *sa;
	
	j = json_array_get(json_object_get(j, "params"), 0);
	assert((j = json_object_get(j, "data")));
	assert((sa = json_string_value(j)));
	return blktmpl_jansson_submit_data_check(sa, level);
}

static void blktmpl_jansson_propose() {
	blktemplate_t * const tmpl = blktmpl_create();
	const char *sa;
	json_t *j, *ja, *jb;
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\"}", simple_time_rcvd));
	
	assert((j = blktmpl_propose_jansson(tmpl, 0, false)));
	check_request(j, blkmk_supported_rules, NULL);
	
	ja = json_array_get(json_object_get(j, "params"), 0);
	assert((jb = json_object_get(ja, "mode")));
	assert((sa = json_string_value(jb)));
	assert(!strcmp(sa, "proposal"));
	assert((jb = json_object_get(ja, "workid")));
	assert((sa = json_string_value(jb)));
	assert(!strcmp(sa, "mywork"));
	blktmpl_jansson_propose_check(j, 2);
	json_decref(j);
	
	tmpl->mutations |= BMAb_COINBASE;
	assert((j = blktmpl_propose_jansson(tmpl, 0, false)));
	check_request(j, blkmk_supported_rules, NULL);
	blktmpl_jansson_propose_check(j, 1);
	json_decref(j);
	
	tmpl->mutations |= BMAb_TRUNCATE;
	assert((j = blktmpl_propose_jansson(tmpl, 0, false)));
	check_request(j, blkmk_supported_rules, NULL);
	blktmpl_jansson_propose_check(j, 0);
	json_decref(j);
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_submit() {
	blktemplate_t * const tmpl = blktmpl_create();
	const char *sa;
	uint8_t data[76];
	int16_t i16;
	unsigned int dataid;
	json_t *j, *ja, *jb, *jc;
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\",\"mutable\":[\"submit/coinbase\",\"submit/truncate\",\"coinbase/append\"]}", simple_time_rcvd));
	
	assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid));
	
	assert((j = blkmk_submit_foreign_jansson(tmpl, data, 0, 0x12345678)));
	assert((ja = json_object_get(j, "params")));
	assert(json_is_array(ja));
	assert(json_array_size(ja) >= 1);
	assert((sa = json_string_value(json_array_get(ja, 0))));
	blktmpl_jansson_submit_data_check(sa, 2);
	if (json_array_size(ja) >= 2) {
		assert(json_is_object((jb = json_array_get(ja, 1))));
		assert(!json_object_get(jb, "workid"));
	}
	json_decref(j);
	
	assert((j = blkmk_submit_jansson(tmpl, data, 0, 0x12345678)));
	assert(json_object_get(j, "id"));
	assert((ja = json_object_get(j, "method")));
	assert((sa = json_string_value(ja)));
	assert(!strcmp(sa, "submitblock"));
	assert((ja = json_object_get(j, "params")));
	assert(json_is_array(ja));
	assert(json_array_size(ja) >= 2);
	assert((sa = json_string_value(json_array_get(ja, 0))));
	blktmpl_jansson_submit_data_check(sa, 0);
	assert(!memcmp(&sa[72], "512a63f45f96f0269a2d23ccd96bcf0322ee4f60254748e30b89e2b59431aba16d030000ff7f001d12345678", 64));  // merkle root
	assert(!memcmp(&sa[152], "12345678", 8));  // nonce
	assert(json_is_object((jb = json_array_get(ja, 1))));
	assert((jc = json_object_get(jb, "workid")));
	assert((sa = json_string_value(jc)));
	assert(!strcmp(sa, "mywork"));
	json_decref(j);
	
	assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid));
	
	assert((j = blkmk_submit_jansson(tmpl, data, dataid, 0x12345678)));
	assert((ja = json_object_get(j, "params")));
	assert(json_is_array(ja));
	assert(json_array_size(ja) >= 2);
	assert((sa = json_string_value(json_array_get(ja, 0))));
	blktmpl_jansson_submit_data_check(sa, -1);
	// TODO: Check inserted dataid
	assert(json_is_object((jb = json_array_get(ja, 1))));
	assert((jc = json_object_get(jb, "workid")));
	assert((sa = json_string_value(jc)));
	assert(!strcmp(sa, "mywork"));
	json_decref(j);
	
	blktmpl_free(tmpl);
}

static void blktmpl_jansson_submitm() {
	blktemplate_t * const tmpl = blktmpl_create();
	const char *sa;
	uint8_t data[76], *cbtxn, *branches, extranonce[10];
	size_t cbextranonceoffset, cbtxnsize;
	int branchcount;
	int16_t i16;
	json_t *j, *ja, *jb, *jc;
	
	assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\",\"mutable\":[\"submit/coinbase\",\"submit/truncate\",\"coinbase/append\"]}", simple_time_rcvd));
	
	assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, 1, false));
	free(cbtxn);
	free(branches);
	memset(&data[36], '\xee', 32);  // merkle root, must be provided by caller
	
	extranonce[0] = 11;
	assert((j = blkmk_submitm_jansson(tmpl, data, extranonce, 1, 0x12345678, false)));
	assert(json_object_get(j, "id"));
	assert((ja = json_object_get(j, "method")));
	assert((sa = json_string_value(ja)));
	assert(!strcmp(sa, "submitblock"));
	assert((ja = json_object_get(j, "params")));
	assert(json_is_array(ja));
	assert(json_array_size(ja) >= 2);
	assert((sa = json_string_value(json_array_get(ja, 0))));
	blktmpl_jansson_submit_data_check(sa, -1);
	assert(!strcmp(&sa[160], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08010404deadbeef0b333333330100100000015100000000"));
	assert(json_is_object((jb = json_array_get(ja, 1))));
	assert((jc = json_object_get(jb, "workid")));
	assert((sa = json_string_value(jc)));
	assert(!strcmp(sa, "mywork"));
	json_decref(j);
	
	extranonce[0] = 22;
	assert((j = blkmk_submitm_jansson(tmpl, data, extranonce, 1, 0x12345678, true)));
	assert((ja = json_object_get(j, "params")));
	assert(json_is_array(ja));
	assert(json_array_size(ja) >= 2);
	assert((sa = json_string_value(json_array_get(ja, 0))));
	blktmpl_jansson_submit_data_check(sa, -1);
	assert(!strcmp(&sa[160], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08010404deadbeef1633333333010010000001510000000001000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa0022222222010010000001510000000001000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f000000000044444444010010000001510000000001000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000"));
	json_decref(j);
	
	assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, 3, false));
	free(cbtxn);
	free(branches);
	
	extranonce[0] = 0x11;
	extranonce[1] = 0x22;
	extranonce[2] = 0x33;
	assert((j = blkmk_submitm_jansson(tmpl, data, extranonce, 3, 0x12345678, false)));
	assert((ja = json_object_get(j, "params")));
	assert(json_is_array(ja));
	assert(json_array_size(ja) >= 2);
	assert((sa = json_string_value(json_array_get(ja, 0))));
	blktmpl_jansson_submit_data_check(sa, -1);
	assert(!strcmp(&sa[160], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0a010404deadbeef112233333333330100100000015100000000"));
	json_decref(j);
	
	extranonce[2] = 0xed;
	assert((j = blkmk_submitm_jansson(tmpl, data, extranonce, 3, 0x12345678, true)));
	assert((ja = json_object_get(j, "params")));
	assert(json_is_array(ja));
	assert(json_array_size(ja) >= 2);
	assert((sa = json_string_value(json_array_get(ja, 0))));
	blktmpl_jansson_submit_data_check(sa, -1);
	assert(!strcmp(&sa[160], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0a010404deadbeef1122ed33333333010010000001510000000001000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa0022222222010010000001510000000001000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f000000000044444444010010000001510000000001000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000"));
	json_decref(j);
	
	blktmpl_free(tmpl);
}

int main() {
	blkmk_sha256_impl = my_sha256;
	
	puts("capabilityname");
	capabilityname_test();
	
	puts("blktxn");
	blktxn_test('\0');
	blktxn_test('\xa5');
	blktxn_test('\xff');
	
	puts("blktmpl");
	blktmpl_test();
	
	puts("blktmpl_request_jansson");
	blktmpl_request_jansson_test_old();
	blktmpl_request_jansson_test_custom_rulelist();
	blktmpl_request_jansson_test_custom_caps();
	blktmpl_request_jansson_test_longpoll();
	
	puts("blktmpl_jansson");
	blktmpl_jansson_simple();
	blktmpl_jansson_bip22_required();
	blktmpl_jansson_bip22_longpoll();
	blktmpl_jansson_bip23_bpe();
	blktmpl_jansson_bip23_mutations();
	blktmpl_jansson_bip23_abbrev();
	blktmpl_jansson_bip9();
	blktmpl_jansson_propose();
	blktmpl_jansson_submit();
	blktmpl_jansson_submitm();
}
{'fraction_non_alphanumeric': 0.1822735749021902, 'fraction_numerical': 0.17571026362938316, 'mean_word_length': 7.276441216522923, 'pattern_counts': {'":': 352, '<': 39, '<?xml version=': 0, '>': 333, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 475, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5742179', 'n_tokens_mistral': 29534, 'n_tokens_neox': 22289, 'n_words': 2491}