Commit 69d2ee810d7d5580052f2c91a427a58e41c3aa7a

Con Kolivas 2014-03-15T23:37:47

Add helper functions for creating script signature templates and beging building template.

diff --git a/cgminer.c b/cgminer.c
index 3e5bb0b..1bd697a 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -2204,11 +2204,14 @@ static void gbt_merkle_bins(struct pool *pool, json_t *transaction_arr)
 
 static bool gbt_solo_decode(struct pool *pool, json_t *res_val)
 {
+	json_t *transaction_arr, *coinbase_aux;
 	const char *previousblockhash;
 	unsigned char hash_swap[32];
-	json_t *transaction_arr;
 	const char *target;
+	int coinbasevalue;
+	const char *flags;
 	const char *bits;
+	int ofs = 0, len;
 	int version;
 	int curtime;
 	int height;
@@ -2220,8 +2223,11 @@ static bool gbt_solo_decode(struct pool *pool, json_t *res_val)
 	curtime = json_integer_value(json_object_get(res_val, "curtime"));
 	bits = json_string_value(json_object_get(res_val, "bits"));
 	height = json_integer_value(json_object_get(res_val, "height"));
+	coinbasevalue = json_integer_value(json_object_get(res_val, "coinbasevalue"));
+	coinbase_aux = json_object_get(res_val, "coinbaseaux");
+	flags = json_string_value(json_object_get(coinbase_aux, "flags"));
 
-	if (!previousblockhash || !target || !version || !curtime || !bits || !height) {
+	if (!previousblockhash || !target || !version || !curtime || !bits || !coinbase_aux || !flags) {
 		applog(LOG_ERR, "Pool %d JSON failed to decode GBT", pool->pool_no);
 		return false;
 	}
@@ -2232,6 +2238,7 @@ static bool gbt_solo_decode(struct pool *pool, json_t *res_val)
 	applog(LOG_DEBUG, "curtime: %d", curtime);
 	applog(LOG_DEBUG, "bits: %s", bits);
 	applog(LOG_DEBUG, "height: %d", height);
+	applog(LOG_DEBUG, "flags: %s", flags);
 
 	cg_wlock(&pool->gbt_lock);
 	hex2bin(hash_swap, previousblockhash, 32);
@@ -2242,8 +2249,20 @@ static bool gbt_solo_decode(struct pool *pool, json_t *res_val)
 
 	pool->gbt_version = htobe32(version);
 	pool->curtime = htobe32(curtime);
+	pool->nValue = coinbasevalue;
 	hex2bin((unsigned char *)&pool->gbt_bits, bits, 4);
 	gbt_merkle_bins(pool, transaction_arr);
+
+	/* Put block height at start of template */
+	ofs = ser_number(pool->scriptsig_template, height);
+	/* Followed by flags */
+	len = strlen(flags) / 2;
+	hex2bin(pool->scriptsig_template + ofs, flags, len);
+	ofs += len;
+	/* Followed by timestamp */
+	ofs += ser_number(pool->scriptsig_template + ofs, time(NULL));
+	/* Followed by extranonce size, fixed at 16 */
+	pool->scriptsig_template[ofs++] = 16;
 	cg_wunlock(&pool->gbt_lock);
 
 	return true;
@@ -6273,6 +6292,8 @@ static bool stratum_works(struct pool *pool)
 	return true;
 }
 
+static const char scriptsig_suffix[] = { 0x07, 0x63, 0x67, 0x6d, 0x69, 0x6e, 0x65, 0x72 };
+
 static bool setup_gbt_solo(CURL *curl, struct pool *pool)
 {
 	char s[256];
@@ -6297,6 +6318,7 @@ static bool setup_gbt_solo(CURL *curl, struct pool *pool)
 	}
 	applog(LOG_DEBUG, "Bitcoin address %s is valid", opt_btc_address);
 	ret = true;
+	address_to_pubkeyhash(pool->script_pubkey, opt_btc_address);
 
 out:
 	return ret;
diff --git a/miner.h b/miner.h
index ddbe4cd..9072e15 100644
--- a/miner.h
+++ b/miner.h
@@ -1261,6 +1261,9 @@ struct pool {
 	unsigned char merklebin[16 * 32];
 	int transactions;
 	unsigned char **txn_data;
+	unsigned char scriptsig_template[20];
+	unsigned char script_pubkey[25];
+	int nValue;
 
 	/* Shared by both stratum & GBT */
 	unsigned char *coinbase;
diff --git a/util.c b/util.c
index 54e88cb..bae35b3 100644
--- a/util.c
+++ b/util.c
@@ -668,6 +668,109 @@ bool hex2bin(unsigned char *p, const char *hexstr, size_t len)
 	return ret;
 }
 
+static const int b58tobin_tbl[] = {
+	-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
+};
+
+/* b58bin should always be at least 25 bytes long and already checked to be
+ * valid. */
+void b58tobin(unsigned char *b58bin, const char *b58)
+{
+	uint32_t c, bin32[7];
+	int len, i, j;
+	uint64_t t;
+
+	memset(bin32, 0, 7 * sizeof(uint32_t));
+	len = strlen(b58);
+	for (i = 0; i < len; i++) {
+		c = b58[i];
+		c = b58tobin_tbl[c];
+		for (j = 7; j >= 0; j--) {
+			t = ((uint64_t)bin32[j]) * 58 + c;
+			c = (t & 0x3f00000000ull) >> 32;
+			bin32[j] = t & 0xffffffffull;
+		}
+	}
+	*(b58bin++) = bin32[0] & 0xff;
+	for (i = 2; i < 7; i++) {
+		*((uint32_t *)b58bin) = htobe32(bin32[i]);
+		b58bin += sizeof(uint32_t);
+	}
+}
+
+void address_to_pubkeyhash(unsigned char *pkh, const char *addr)
+{
+	unsigned char b58bin[25];
+
+	b58tobin(b58bin, addr);
+	pkh[0] = 0x76;
+	pkh[1] = 0xa9;
+	pkh[2] = 0x14;
+	memcpy(&pkh[3], &b58bin[1], 20);
+	pkh[23] = 0x88;
+	pkh[24] = 0xac;
+}
+
+/*  For encoding nHeight into coinbase */
+int ser_number(unsigned char *s, uint32_t val)
+{
+	int i = 1;
+
+	s[0] = i;
+	while (val > 127) {
+		s[0] = ++i;
+		s[i] = val % 256;
+		val /= 256;
+	}
+	s[++i] = val;
+	return i;
+}
+
+/* For encoding variable length strings */
+unsigned char *ser_string(char *s, int *slen)
+{
+	size_t len = strlen(s);
+	unsigned char *ret;
+
+	ret = malloc(1 + len + 8); // Leave room for largest size
+	if (unlikely(!ret))
+		quit(1, "Failed to malloc ret in ser_string");
+	if (len < 253) {
+		ret[0] = len;
+		memcpy(ret + 1, s, len);
+		*slen = len + 1;
+	} else if (len < 0x10000) {
+		uint16_t *u16 = (uint16_t *)&ret[1];
+
+		ret[0] = 253;
+		*u16 = htobe16(len);
+		memcpy(ret + 3, s, len);
+		*slen = len + 3;
+	} else if (len < 0x100000000ul) {
+		uint32_t *u32 = (uint32_t *)&ret[1];
+
+		ret[0] = 254;
+		*u32 = htobe32(len);
+		memcpy(ret + 5, s, len);
+		*slen = len + 5;
+	} else {
+		uint64_t *u64 = (uint64_t *)&ret[1];
+
+		ret[0] = 255;
+		*u64 = htobe64(len);
+		memcpy(ret + 9, s, len);
+		*slen = len + 9;
+	}
+	return ret;
+}
+
 bool fulltest(const unsigned char *hash, const unsigned char *target)
 {
 	uint32_t *hash32 = (uint32_t *)hash;
diff --git a/util.h b/util.h
index 566f3a7..9365e46 100644
--- a/util.h
+++ b/util.h
@@ -106,6 +106,10 @@ struct thr_info;
 struct pool;
 enum dev_reason;
 struct cgpu_info;
+void b58tobin(unsigned char *b58bin, const char *b58);
+void address_to_pubkeyhash(unsigned char *pkh, const char *addr);
+int ser_number(unsigned char *s, uint32_t val);
+unsigned char *ser_string(char *s, int *slen);
 int thr_info_create(struct thr_info *thr, pthread_attr_t *attr, void *(*start) (void *), void *arg);
 void thr_info_cancel(struct thr_info *thr);
 void cgtime(struct timeval *tv);