Merge branch 'beta' into mergemaster
# Conflicts: # src/main.cpp
This commit is contained in:
@@ -118,19 +118,18 @@ class AuthServiceProxy(object):
|
||||
try:
|
||||
self.__conn.request(method, path, postdata, headers)
|
||||
return self._get_response()
|
||||
except httplib.BadStatusLine as e:
|
||||
if e.line == "''": # if connection was closed, try again
|
||||
except Exception as e:
|
||||
# If connection was closed, try again.
|
||||
# Python 3.5+ raises BrokenPipeError instead of BadStatusLine when the connection was reset.
|
||||
# ConnectionResetError happens on FreeBSD with Python 3.4.
|
||||
# These classes don't exist in Python 2.x, so we can't refer to them directly.
|
||||
if ((isinstance(e, httplib.BadStatusLine) and e.line == "''")
|
||||
or e.__class__.__name__ in ('BrokenPipeError', 'ConnectionResetError')):
|
||||
self.__conn.close()
|
||||
self.__conn.request(method, path, postdata, headers)
|
||||
return self._get_response()
|
||||
else:
|
||||
raise
|
||||
except (BrokenPipeError,ConnectionResetError):
|
||||
# Python 3.5+ raises BrokenPipeError instead of BadStatusLine when the connection was reset
|
||||
# ConnectionResetError happens on FreeBSD with Python 3.4
|
||||
self.__conn.close()
|
||||
self.__conn.request(method, path, postdata, headers)
|
||||
return self._get_response()
|
||||
|
||||
def __call__(self, *args):
|
||||
AuthServiceProxy.__id_count += 1
|
||||
|
||||
@@ -3,14 +3,17 @@
|
||||
# and for constructing a getheaders message
|
||||
#
|
||||
|
||||
from mininode import *
|
||||
from mininode import CBlock, CBlockHeader, CBlockLocator, CTransaction, msg_block, msg_headers, msg_tx
|
||||
|
||||
import sys
|
||||
import cStringIO
|
||||
import dbm
|
||||
|
||||
class BlockStore(object):
|
||||
def __init__(self, datadir):
|
||||
self.blockDB = dbm.open(datadir + "/blocks", 'c')
|
||||
self.currentBlock = 0L
|
||||
|
||||
|
||||
def close(self):
|
||||
self.blockDB.close()
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#
|
||||
|
||||
from mininode import *
|
||||
from script import CScript, CScriptOp
|
||||
from mininode import CBlock, CTransaction, CTxIn, CTxOut, COutPoint
|
||||
from script import CScript, OP_0, OP_EQUAL, OP_HASH160
|
||||
|
||||
# Create a block (with regtest difficulty)
|
||||
def create_block(hashprev, coinbase, nTime=None):
|
||||
def create_block(hashprev, coinbase, nTime=None, nBits=None):
|
||||
block = CBlock()
|
||||
if nTime is None:
|
||||
import time
|
||||
@@ -16,7 +16,10 @@ def create_block(hashprev, coinbase, nTime=None):
|
||||
else:
|
||||
block.nTime = nTime
|
||||
block.hashPrevBlock = hashprev
|
||||
block.nBits = 0x207fffff # Will break after a difficulty adjustment...
|
||||
if nBits is None:
|
||||
block.nBits = 0x200f0f0f # Will break after a difficulty adjustment...
|
||||
else:
|
||||
block.nBits = nBits
|
||||
block.vtx.append(coinbase)
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
block.calc_sha256()
|
||||
@@ -43,14 +46,24 @@ def create_coinbase(heightAdjust = 0):
|
||||
global counter
|
||||
coinbase = CTransaction()
|
||||
coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff),
|
||||
ser_string(serialize_script_num(counter+heightAdjust)), 0xffffffff))
|
||||
CScript([counter+heightAdjust, OP_0]), 0xffffffff))
|
||||
counter += 1
|
||||
coinbaseoutput = CTxOut()
|
||||
coinbaseoutput.nValue = 50*100000000
|
||||
coinbaseoutput.nValue = int(12.5*100000000)
|
||||
halvings = int((counter+heightAdjust)/150) # regtest
|
||||
coinbaseoutput.nValue >>= halvings
|
||||
coinbaseoutput.scriptPubKey = ""
|
||||
coinbase.vout = [ coinbaseoutput ]
|
||||
if halvings == 0: # regtest
|
||||
froutput = CTxOut()
|
||||
froutput.nValue = coinbaseoutput.nValue / 5
|
||||
# regtest
|
||||
fraddr = bytearray([0x67, 0x08, 0xe6, 0x67, 0x0d, 0xb0, 0xb9, 0x50,
|
||||
0xda, 0xc6, 0x80, 0x31, 0x02, 0x5c, 0xc5, 0xb6,
|
||||
0x32, 0x13, 0xa4, 0x91])
|
||||
froutput.scriptPubKey = CScript([OP_HASH160, fraddr, OP_EQUAL])
|
||||
coinbaseoutput.nValue -= froutput.nValue
|
||||
coinbase.vout = [ coinbaseoutput, froutput ]
|
||||
coinbase.calc_sha256()
|
||||
return coinbase
|
||||
|
||||
|
||||
@@ -4,10 +4,13 @@
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#
|
||||
|
||||
from mininode import *
|
||||
from mininode import CBlock, CTransaction, CInv, NodeConn, NodeConnCB, \
|
||||
msg_inv, msg_getheaders, msg_ping, msg_mempool, mininode_lock, MAX_INV_SZ
|
||||
from blockstore import BlockStore, TxStore
|
||||
from util import p2p_port
|
||||
|
||||
import time
|
||||
|
||||
'''
|
||||
This is a tool for comparing two or more bitcoinds to each other
|
||||
using a script provided.
|
||||
@@ -25,8 +28,6 @@ generator that returns TestInstance objects. See below for definition.
|
||||
# on_getheaders: provide headers via BlockStore
|
||||
# on_getdata: provide blocks via BlockStore
|
||||
|
||||
global mininode_lock
|
||||
|
||||
def wait_until(predicate, attempts=float('inf'), timeout=float('inf')):
|
||||
attempt = 0
|
||||
elapsed = 0
|
||||
|
||||
293
qa/rpc-tests/test_framework/equihash.py
Executable file
293
qa/rpc-tests/test_framework/equihash.py
Executable file
@@ -0,0 +1,293 @@
|
||||
from operator import itemgetter
|
||||
import struct
|
||||
|
||||
DEBUG = False
|
||||
VERBOSE = False
|
||||
|
||||
|
||||
word_size = 32
|
||||
word_mask = (1<<word_size)-1
|
||||
|
||||
def expand_array(inp, out_len, bit_len, byte_pad=0):
|
||||
assert bit_len >= 8 and word_size >= 7+bit_len
|
||||
bit_len_mask = (1<<bit_len)-1
|
||||
|
||||
out_width = (bit_len+7)/8 + byte_pad
|
||||
assert out_len == 8*out_width*len(inp)/bit_len
|
||||
out = bytearray(out_len)
|
||||
|
||||
bit_len_mask = (1 << bit_len) - 1
|
||||
|
||||
# The acc_bits least-significant bits of acc_value represent a bit sequence
|
||||
# in big-endian order.
|
||||
acc_bits = 0;
|
||||
acc_value = 0;
|
||||
|
||||
j = 0
|
||||
for i in xrange(len(inp)):
|
||||
acc_value = ((acc_value << 8) & word_mask) | inp[i]
|
||||
acc_bits += 8
|
||||
|
||||
# When we have bit_len or more bits in the accumulator, write the next
|
||||
# output element.
|
||||
if acc_bits >= bit_len:
|
||||
acc_bits -= bit_len
|
||||
for x in xrange(byte_pad, out_width):
|
||||
out[j+x] = (
|
||||
# Big-endian
|
||||
acc_value >> (acc_bits+(8*(out_width-x-1)))
|
||||
) & (
|
||||
# Apply bit_len_mask across byte boundaries
|
||||
(bit_len_mask >> (8*(out_width-x-1))) & 0xFF
|
||||
)
|
||||
j += out_width
|
||||
|
||||
return out
|
||||
|
||||
def compress_array(inp, out_len, bit_len, byte_pad=0):
|
||||
assert bit_len >= 8 and word_size >= 7+bit_len
|
||||
|
||||
in_width = (bit_len+7)/8 + byte_pad
|
||||
assert out_len == bit_len*len(inp)/(8*in_width)
|
||||
out = bytearray(out_len)
|
||||
|
||||
bit_len_mask = (1 << bit_len) - 1
|
||||
|
||||
# The acc_bits least-significant bits of acc_value represent a bit sequence
|
||||
# in big-endian order.
|
||||
acc_bits = 0;
|
||||
acc_value = 0;
|
||||
|
||||
j = 0
|
||||
for i in xrange(out_len):
|
||||
# When we have fewer than 8 bits left in the accumulator, read the next
|
||||
# input element.
|
||||
if acc_bits < 8:
|
||||
acc_value = ((acc_value << bit_len) & word_mask) | inp[j]
|
||||
for x in xrange(byte_pad, in_width):
|
||||
acc_value = acc_value | (
|
||||
(
|
||||
# Apply bit_len_mask across byte boundaries
|
||||
inp[j+x] & ((bit_len_mask >> (8*(in_width-x-1))) & 0xFF)
|
||||
) << (8*(in_width-x-1))); # Big-endian
|
||||
j += in_width
|
||||
acc_bits += bit_len
|
||||
|
||||
acc_bits -= 8
|
||||
out[i] = (acc_value >> acc_bits) & 0xFF
|
||||
|
||||
return out
|
||||
|
||||
def get_indices_from_minimal(minimal, bit_len):
|
||||
eh_index_size = 4
|
||||
assert (bit_len+7)/8 <= eh_index_size
|
||||
len_indices = 8*eh_index_size*len(minimal)/bit_len
|
||||
byte_pad = eh_index_size - (bit_len+7)/8
|
||||
expanded = expand_array(minimal, len_indices, bit_len, byte_pad)
|
||||
return [struct.unpack('>I', expanded[i:i+4])[0] for i in range(0, len_indices, eh_index_size)]
|
||||
|
||||
def get_minimal_from_indices(indices, bit_len):
|
||||
eh_index_size = 4
|
||||
assert (bit_len+7)/8 <= eh_index_size
|
||||
len_indices = len(indices)*eh_index_size
|
||||
min_len = bit_len*len_indices/(8*eh_index_size)
|
||||
byte_pad = eh_index_size - (bit_len+7)/8
|
||||
byte_indices = bytearray(''.join([struct.pack('>I', i) for i in indices]))
|
||||
return compress_array(byte_indices, min_len, bit_len, byte_pad)
|
||||
|
||||
|
||||
def hash_nonce(digest, nonce):
|
||||
for i in range(8):
|
||||
digest.update(struct.pack('<I', nonce >> (32*i)))
|
||||
|
||||
def hash_xi(digest, xi):
|
||||
digest.update(struct.pack('<I', xi))
|
||||
return digest # For chaining
|
||||
|
||||
def count_zeroes(h):
|
||||
# Convert to binary string
|
||||
if type(h) == bytearray:
|
||||
h = ''.join('{0:08b}'.format(x, 'b') for x in h)
|
||||
else:
|
||||
h = ''.join('{0:08b}'.format(ord(x), 'b') for x in h)
|
||||
# Count leading zeroes
|
||||
return (h+'1').index('1')
|
||||
|
||||
def has_collision(ha, hb, i, l):
|
||||
res = [ha[j] == hb[j] for j in range((i-1)*l/8, i*l/8)]
|
||||
return reduce(lambda x, y: x and y, res)
|
||||
|
||||
def distinct_indices(a, b):
|
||||
for i in a:
|
||||
for j in b:
|
||||
if i == j:
|
||||
return False
|
||||
return True
|
||||
|
||||
def xor(ha, hb):
|
||||
return bytearray(a^b for a,b in zip(ha,hb))
|
||||
|
||||
def gbp_basic(digest, n, k):
|
||||
'''Implementation of Basic Wagner's algorithm for the GBP.'''
|
||||
validate_params(n, k)
|
||||
collision_length = n/(k+1)
|
||||
hash_length = (k+1)*((collision_length+7)//8)
|
||||
indices_per_hash_output = 512/n
|
||||
|
||||
# 1) Generate first list
|
||||
if DEBUG: print 'Generating first list'
|
||||
X = []
|
||||
tmp_hash = ''
|
||||
for i in range(0, 2**(collision_length+1)):
|
||||
r = i % indices_per_hash_output
|
||||
if r == 0:
|
||||
# X_i = H(I||V||x_i)
|
||||
curr_digest = digest.copy()
|
||||
hash_xi(curr_digest, i/indices_per_hash_output)
|
||||
tmp_hash = curr_digest.digest()
|
||||
X.append((
|
||||
expand_array(bytearray(tmp_hash[r*n/8:(r+1)*n/8]),
|
||||
hash_length, collision_length),
|
||||
(i,)
|
||||
))
|
||||
|
||||
# 3) Repeat step 2 until 2n/(k+1) bits remain
|
||||
for i in range(1, k):
|
||||
if DEBUG: print 'Round %d:' % i
|
||||
|
||||
# 2a) Sort the list
|
||||
if DEBUG: print '- Sorting list'
|
||||
X.sort(key=itemgetter(0))
|
||||
if DEBUG and VERBOSE:
|
||||
for Xi in X[-32:]:
|
||||
print '%s %s' % (print_hash(Xi[0]), Xi[1])
|
||||
|
||||
if DEBUG: print '- Finding collisions'
|
||||
Xc = []
|
||||
while len(X) > 0:
|
||||
# 2b) Find next set of unordered pairs with collisions on first n/(k+1) bits
|
||||
j = 1
|
||||
while j < len(X):
|
||||
if not has_collision(X[-1][0], X[-1-j][0], i, collision_length):
|
||||
break
|
||||
j += 1
|
||||
|
||||
# 2c) Store tuples (X_i ^ X_j, (i, j)) on the table
|
||||
for l in range(0, j-1):
|
||||
for m in range(l+1, j):
|
||||
# Check that there are no duplicate indices in tuples i and j
|
||||
if distinct_indices(X[-1-l][1], X[-1-m][1]):
|
||||
if X[-1-l][1][0] < X[-1-m][1][0]:
|
||||
concat = X[-1-l][1] + X[-1-m][1]
|
||||
else:
|
||||
concat = X[-1-m][1] + X[-1-l][1]
|
||||
Xc.append((xor(X[-1-l][0], X[-1-m][0]), concat))
|
||||
|
||||
# 2d) Drop this set
|
||||
while j > 0:
|
||||
X.pop(-1)
|
||||
j -= 1
|
||||
# 2e) Replace previous list with new list
|
||||
X = Xc
|
||||
|
||||
# k+1) Find a collision on last 2n(k+1) bits
|
||||
if DEBUG:
|
||||
print 'Final round:'
|
||||
print '- Sorting list'
|
||||
X.sort(key=itemgetter(0))
|
||||
if DEBUG and VERBOSE:
|
||||
for Xi in X[-32:]:
|
||||
print '%s %s' % (print_hash(Xi[0]), Xi[1])
|
||||
if DEBUG: print '- Finding collisions'
|
||||
solns = []
|
||||
while len(X) > 0:
|
||||
j = 1
|
||||
while j < len(X):
|
||||
if not (has_collision(X[-1][0], X[-1-j][0], k, collision_length) and
|
||||
has_collision(X[-1][0], X[-1-j][0], k+1, collision_length)):
|
||||
break
|
||||
j += 1
|
||||
|
||||
for l in range(0, j-1):
|
||||
for m in range(l+1, j):
|
||||
res = xor(X[-1-l][0], X[-1-m][0])
|
||||
if count_zeroes(res) == 8*hash_length and distinct_indices(X[-1-l][1], X[-1-m][1]):
|
||||
if DEBUG and VERBOSE:
|
||||
print 'Found solution:'
|
||||
print '- %s %s' % (print_hash(X[-1-l][0]), X[-1-l][1])
|
||||
print '- %s %s' % (print_hash(X[-1-m][0]), X[-1-m][1])
|
||||
if X[-1-l][1][0] < X[-1-m][1][0]:
|
||||
solns.append(list(X[-1-l][1] + X[-1-m][1]))
|
||||
else:
|
||||
solns.append(list(X[-1-m][1] + X[-1-l][1]))
|
||||
|
||||
# 2d) Drop this set
|
||||
while j > 0:
|
||||
X.pop(-1)
|
||||
j -= 1
|
||||
return [get_minimal_from_indices(soln, collision_length+1) for soln in solns]
|
||||
|
||||
def gbp_validate(digest, minimal, n, k):
|
||||
validate_params(n, k)
|
||||
collision_length = n/(k+1)
|
||||
hash_length = (k+1)*((collision_length+7)//8)
|
||||
indices_per_hash_output = 512/n
|
||||
solution_width = (1 << k)*(collision_length+1)//8
|
||||
|
||||
if len(minimal) != solution_width:
|
||||
print 'Invalid solution length: %d (expected %d)' % \
|
||||
(len(minimal), solution_width)
|
||||
return False
|
||||
|
||||
X = []
|
||||
for i in get_indices_from_minimal(minimal, collision_length+1):
|
||||
r = i % indices_per_hash_output
|
||||
# X_i = H(I||V||x_i)
|
||||
curr_digest = digest.copy()
|
||||
hash_xi(curr_digest, i/indices_per_hash_output)
|
||||
tmp_hash = curr_digest.digest()
|
||||
X.append((
|
||||
expand_array(bytearray(tmp_hash[r*n/8:(r+1)*n/8]),
|
||||
hash_length, collision_length),
|
||||
(i,)
|
||||
))
|
||||
|
||||
for r in range(1, k+1):
|
||||
Xc = []
|
||||
for i in range(0, len(X), 2):
|
||||
if not has_collision(X[i][0], X[i+1][0], r, collision_length):
|
||||
print 'Invalid solution: invalid collision length between StepRows'
|
||||
return False
|
||||
if X[i+1][1][0] < X[i][1][0]:
|
||||
print 'Invalid solution: Index tree incorrectly ordered'
|
||||
return False
|
||||
if not distinct_indices(X[i][1], X[i+1][1]):
|
||||
print 'Invalid solution: duplicate indices'
|
||||
return False
|
||||
Xc.append((xor(X[i][0], X[i+1][0]), X[i][1] + X[i+1][1]))
|
||||
X = Xc
|
||||
|
||||
if len(X) != 1:
|
||||
print 'Invalid solution: incorrect length after end of rounds: %d' % len(X)
|
||||
return False
|
||||
|
||||
if count_zeroes(X[0][0]) != 8*hash_length:
|
||||
print 'Invalid solution: incorrect number of zeroes: %d' % count_zeroes(X[0][0])
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def zcash_person(n, k):
|
||||
return b'ZcashPoW' + struct.pack('<II', n, k)
|
||||
|
||||
def print_hash(h):
|
||||
if type(h) == bytearray:
|
||||
return ''.join('{0:02x}'.format(x, 'x') for x in h)
|
||||
else:
|
||||
return ''.join('{0:02x}'.format(ord(x), 'x') for x in h)
|
||||
|
||||
def validate_params(n, k):
|
||||
if (k >= n):
|
||||
raise ValueError('n must be larger than k')
|
||||
if (((n/(k+1))+1) >= 32):
|
||||
raise ValueError('Parameters must satisfy n/(k+1)+1 < 32')
|
||||
@@ -30,9 +30,18 @@ from threading import RLock
|
||||
from threading import Thread
|
||||
import logging
|
||||
import copy
|
||||
from pyblake2 import blake2b
|
||||
|
||||
from .equihash import (
|
||||
gbp_basic,
|
||||
gbp_validate,
|
||||
hash_nonce,
|
||||
zcash_person,
|
||||
)
|
||||
|
||||
OVERWINTER_PROTO_VERSION = 170003
|
||||
BIP0031_VERSION = 60000
|
||||
MY_VERSION = 60001 # past bip-31 for ping/pong
|
||||
MY_VERSION = 170002 # past bip-31 for ping/pong
|
||||
MY_SUBVERSION = "/python-mininode-tester:0.0.1/"
|
||||
|
||||
MAX_INV_SZ = 50000
|
||||
@@ -234,6 +243,36 @@ def ser_int_vector(l):
|
||||
return r
|
||||
|
||||
|
||||
def deser_char_vector(f):
|
||||
nit = struct.unpack("<B", f.read(1))[0]
|
||||
if nit == 253:
|
||||
nit = struct.unpack("<H", f.read(2))[0]
|
||||
elif nit == 254:
|
||||
nit = struct.unpack("<I", f.read(4))[0]
|
||||
elif nit == 255:
|
||||
nit = struct.unpack("<Q", f.read(8))[0]
|
||||
r = []
|
||||
for i in xrange(nit):
|
||||
t = struct.unpack("<B", f.read(1))[0]
|
||||
r.append(t)
|
||||
return r
|
||||
|
||||
|
||||
def ser_char_vector(l):
|
||||
r = ""
|
||||
if len(l) < 253:
|
||||
r = chr(len(l))
|
||||
elif len(l) < 0x10000:
|
||||
r = chr(253) + struct.pack("<H", len(l))
|
||||
elif len(l) < 0x100000000L:
|
||||
r = chr(254) + struct.pack("<I", len(l))
|
||||
else:
|
||||
r = chr(255) + struct.pack("<Q", len(l))
|
||||
for i in l:
|
||||
r += chr(i)
|
||||
return r
|
||||
|
||||
|
||||
# Objects that map to bitcoind objects, which can be serialized/deserialized
|
||||
|
||||
class CAddress(object):
|
||||
@@ -307,6 +346,154 @@ class CBlockLocator(object):
|
||||
% (self.nVersion, repr(self.vHave))
|
||||
|
||||
|
||||
G1_PREFIX_MASK = 0x02
|
||||
G2_PREFIX_MASK = 0x0a
|
||||
|
||||
class ZCProof(object):
|
||||
def __init__(self):
|
||||
self.g_A = None
|
||||
self.g_A_prime = None
|
||||
self.g_B = None
|
||||
self.g_B_prime = None
|
||||
self.g_C = None
|
||||
self.g_C_prime = None
|
||||
self.g_K = None
|
||||
self.g_H = None
|
||||
|
||||
def deserialize(self, f):
|
||||
def deser_g1(self, f):
|
||||
leadingByte = struct.unpack("<B", f.read(1))[0]
|
||||
return {
|
||||
'y_lsb': leadingByte & 1,
|
||||
'x': f.read(32),
|
||||
}
|
||||
def deser_g2(self, f):
|
||||
leadingByte = struct.unpack("<B", f.read(1))[0]
|
||||
return {
|
||||
'y_gt': leadingByte & 1,
|
||||
'x': f.read(64),
|
||||
}
|
||||
self.g_A = deser_g1(f)
|
||||
self.g_A_prime = deser_g1(f)
|
||||
self.g_B = deser_g2(f)
|
||||
self.g_B_prime = deser_g1(f)
|
||||
self.g_C = deser_g1(f)
|
||||
self.g_C_prime = deser_g1(f)
|
||||
self.g_K = deser_g1(f)
|
||||
self.g_H = deser_g1(f)
|
||||
|
||||
def serialize(self):
|
||||
def ser_g1(self, p):
|
||||
return chr(G1_PREFIX_MASK | p['y_lsb']) + p['x']
|
||||
def ser_g2(self, p):
|
||||
return chr(G2_PREFIX_MASK | p['y_gt']) + p['x']
|
||||
r = ""
|
||||
r += ser_g1(self.g_A)
|
||||
r += ser_g1(self.g_A_prime)
|
||||
r += ser_g2(self.g_B)
|
||||
r += ser_g1(self.g_B_prime)
|
||||
r += ser_g1(self.g_C)
|
||||
r += ser_g1(self.g_C_prime)
|
||||
r += ser_g1(self.g_K)
|
||||
r += ser_g1(self.g_H)
|
||||
return r
|
||||
|
||||
def __repr__(self):
|
||||
return "ZCProof(g_A=%s g_A_prime=%s g_B=%s g_B_prime=%s g_C=%s g_C_prime=%s g_K=%s g_H=%s)" \
|
||||
% (repr(self.g_A), repr(self.g_A_prime),
|
||||
repr(self.g_B), repr(self.g_B_prime),
|
||||
repr(self.g_C), repr(self.g_C_prime),
|
||||
repr(self.g_K), repr(self.g_H))
|
||||
|
||||
|
||||
ZC_NUM_JS_INPUTS = 2
|
||||
ZC_NUM_JS_OUTPUTS = 2
|
||||
|
||||
ZC_NOTEPLAINTEXT_LEADING = 1
|
||||
ZC_V_SIZE = 8
|
||||
ZC_RHO_SIZE = 32
|
||||
ZC_R_SIZE = 32
|
||||
ZC_MEMO_SIZE = 512
|
||||
|
||||
ZC_NOTEPLAINTEXT_SIZE = (
|
||||
ZC_NOTEPLAINTEXT_LEADING +
|
||||
ZC_V_SIZE +
|
||||
ZC_RHO_SIZE +
|
||||
ZC_R_SIZE +
|
||||
ZC_MEMO_SIZE
|
||||
)
|
||||
|
||||
NOTEENCRYPTION_AUTH_BYTES = 16
|
||||
|
||||
ZC_NOTECIPHERTEXT_SIZE = (
|
||||
ZC_NOTEPLAINTEXT_SIZE +
|
||||
NOTEENCRYPTION_AUTH_BYTES
|
||||
)
|
||||
|
||||
class JSDescription(object):
|
||||
def __init__(self):
|
||||
self.vpub_old = 0
|
||||
self.vpub_new = 0
|
||||
self.anchor = 0
|
||||
self.nullifiers = [0] * ZC_NUM_JS_INPUTS
|
||||
self.commitments = [0] * ZC_NUM_JS_OUTPUTS
|
||||
self.onetimePubKey = 0
|
||||
self.randomSeed = 0
|
||||
self.macs = [0] * ZC_NUM_JS_INPUTS
|
||||
self.proof = None
|
||||
self.ciphertexts = [None] * ZC_NUM_JS_OUTPUTS
|
||||
|
||||
def deserialize(self, f):
|
||||
self.vpub_old = struct.unpack("<q", f.read(8))[0]
|
||||
self.vpub_new = struct.unpack("<q", f.read(8))[0]
|
||||
self.anchor = deser_uint256(f)
|
||||
|
||||
self.nullifiers = []
|
||||
for i in range(ZC_NUM_JS_INPUTS):
|
||||
self.nullifiers.append(deser_uint256(f))
|
||||
|
||||
self.commitments = []
|
||||
for i in range(ZC_NUM_JS_OUTPUTS):
|
||||
self.commitments.append(deser_uint256(f))
|
||||
|
||||
self.onetimePubKey = deser_uint256(f)
|
||||
self.randomSeed = deser_uint256(f)
|
||||
|
||||
self.macs = []
|
||||
for i in range(ZC_NUM_JS_INPUTS):
|
||||
self.macs.append(deser_uint256(f))
|
||||
|
||||
self.proof = ZCProof()
|
||||
self.proof.deserialize(f)
|
||||
|
||||
self.ciphertexts = []
|
||||
for i in range(ZC_NUM_JS_OUTPUTS):
|
||||
self.ciphertexts.append(f.read(ZC_NOTECIPHERTEXT_SIZE))
|
||||
|
||||
def serialize(self):
|
||||
r = ""
|
||||
r += struct.pack("<q", self.vpub_old)
|
||||
r += struct.pack("<q", self.vpub_new)
|
||||
r += ser_uint256(self.anchor)
|
||||
for i in range(ZC_NUM_JS_INPUTS):
|
||||
r += ser_uint256(self.nullifiers[i])
|
||||
for i in range(ZC_NUM_JS_OUTPUTS):
|
||||
r += ser_uint256(self.commitments[i])
|
||||
r += ser_uint256(self.onetimePubKey)
|
||||
r += ser_uint256(self.randomSeed)
|
||||
for i in range(ZC_NUM_JS_INPUTS):
|
||||
r += ser_uint256(self.macs[i])
|
||||
r += self.proof.serialize()
|
||||
for i in range(ZC_NUM_JS_OUTPUTS):
|
||||
r += ser_uint256(self.ciphertexts[i])
|
||||
return r
|
||||
|
||||
def __repr__(self):
|
||||
return "JSDescription(vpub_old=%i.%08i vpub_new=%i.%08i anchor=%064x onetimePubKey=%064x randomSeed=%064x proof=%s)" \
|
||||
% (self.vpub_old, self.vpub_new, self.anchor,
|
||||
self.onetimePubKey, self.randomSeed, repr(self.proof))
|
||||
|
||||
|
||||
class COutPoint(object):
|
||||
def __init__(self, hash=0, n=0):
|
||||
self.hash = hash
|
||||
@@ -382,6 +569,9 @@ class CTransaction(object):
|
||||
self.vin = []
|
||||
self.vout = []
|
||||
self.nLockTime = 0
|
||||
self.vjoinsplit = []
|
||||
self.joinSplitPubKey = None
|
||||
self.joinSplitSig = None
|
||||
self.sha256 = None
|
||||
self.hash = None
|
||||
else:
|
||||
@@ -389,6 +579,9 @@ class CTransaction(object):
|
||||
self.vin = copy.deepcopy(tx.vin)
|
||||
self.vout = copy.deepcopy(tx.vout)
|
||||
self.nLockTime = tx.nLockTime
|
||||
self.vjoinsplit = copy.deepcopy(tx.vjoinsplit)
|
||||
self.joinSplitPubKey = tx.joinSplitPubKey
|
||||
self.joinSplitSig = tx.joinSplitSig
|
||||
self.sha256 = None
|
||||
self.hash = None
|
||||
|
||||
@@ -397,6 +590,11 @@ class CTransaction(object):
|
||||
self.vin = deser_vector(f, CTxIn)
|
||||
self.vout = deser_vector(f, CTxOut)
|
||||
self.nLockTime = struct.unpack("<I", f.read(4))[0]
|
||||
if self.nVersion >= 2:
|
||||
self.vjoinsplit = deser_vector(f, JSDescription)
|
||||
if len(self.vjoinsplit) > 0:
|
||||
self.joinSplitPubKey = deser_uint256(f)
|
||||
self.joinSplitSig = f.read(64)
|
||||
self.sha256 = None
|
||||
self.hash = None
|
||||
|
||||
@@ -406,6 +604,11 @@ class CTransaction(object):
|
||||
r += ser_vector(self.vin)
|
||||
r += ser_vector(self.vout)
|
||||
r += struct.pack("<I", self.nLockTime)
|
||||
if self.nVersion >= 2:
|
||||
r += ser_vector(self.vjoinsplit)
|
||||
if len(self.vjoinsplit) > 0:
|
||||
r += ser_uint256(self.joinSplitPubKey)
|
||||
r += self.joinSplitSig
|
||||
return r
|
||||
|
||||
def rehash(self):
|
||||
@@ -425,8 +628,15 @@ class CTransaction(object):
|
||||
return True
|
||||
|
||||
def __repr__(self):
|
||||
return "CTransaction(nVersion=%i vin=%s vout=%s nLockTime=%i)" \
|
||||
r = "CTransaction(nVersion=%i vin=%s vout=%s nLockTime=%i" \
|
||||
% (self.nVersion, repr(self.vin), repr(self.vout), self.nLockTime)
|
||||
if self.nVersion >= 2:
|
||||
r += " vjoinsplit=%s" % repr(self.vjoinsplit)
|
||||
if len(self.vjoinsplit) > 0:
|
||||
r += " joinSplitPubKey=%064x joinSplitSig=%064x" \
|
||||
(self.joinSplitPubKey, self.joinSplitSig)
|
||||
r += ")"
|
||||
return r
|
||||
|
||||
|
||||
class CBlockHeader(object):
|
||||
@@ -437,20 +647,24 @@ class CBlockHeader(object):
|
||||
self.nVersion = header.nVersion
|
||||
self.hashPrevBlock = header.hashPrevBlock
|
||||
self.hashMerkleRoot = header.hashMerkleRoot
|
||||
self.hashReserved = header.hashReserved
|
||||
self.nTime = header.nTime
|
||||
self.nBits = header.nBits
|
||||
self.nNonce = header.nNonce
|
||||
self.nSolution = header.nSolution
|
||||
self.sha256 = header.sha256
|
||||
self.hash = header.hash
|
||||
self.calc_sha256()
|
||||
|
||||
def set_null(self):
|
||||
self.nVersion = 1
|
||||
self.nVersion = 4
|
||||
self.hashPrevBlock = 0
|
||||
self.hashMerkleRoot = 0
|
||||
self.hashReserved = 0
|
||||
self.nTime = 0
|
||||
self.nBits = 0
|
||||
self.nNonce = 0
|
||||
self.nSolution = []
|
||||
self.sha256 = None
|
||||
self.hash = None
|
||||
|
||||
@@ -458,9 +672,11 @@ class CBlockHeader(object):
|
||||
self.nVersion = struct.unpack("<i", f.read(4))[0]
|
||||
self.hashPrevBlock = deser_uint256(f)
|
||||
self.hashMerkleRoot = deser_uint256(f)
|
||||
self.hashReserved = deser_uint256(f)
|
||||
self.nTime = struct.unpack("<I", f.read(4))[0]
|
||||
self.nBits = struct.unpack("<I", f.read(4))[0]
|
||||
self.nNonce = struct.unpack("<I", f.read(4))[0]
|
||||
self.nNonce = deser_uint256(f)
|
||||
self.nSolution = deser_char_vector(f)
|
||||
self.sha256 = None
|
||||
self.hash = None
|
||||
|
||||
@@ -469,9 +685,11 @@ class CBlockHeader(object):
|
||||
r += struct.pack("<i", self.nVersion)
|
||||
r += ser_uint256(self.hashPrevBlock)
|
||||
r += ser_uint256(self.hashMerkleRoot)
|
||||
r += ser_uint256(self.hashReserved)
|
||||
r += struct.pack("<I", self.nTime)
|
||||
r += struct.pack("<I", self.nBits)
|
||||
r += struct.pack("<I", self.nNonce)
|
||||
r += ser_uint256(self.nNonce)
|
||||
r += ser_char_vector(self.nSolution)
|
||||
return r
|
||||
|
||||
def calc_sha256(self):
|
||||
@@ -480,9 +698,11 @@ class CBlockHeader(object):
|
||||
r += struct.pack("<i", self.nVersion)
|
||||
r += ser_uint256(self.hashPrevBlock)
|
||||
r += ser_uint256(self.hashMerkleRoot)
|
||||
r += ser_uint256(self.hashReserved)
|
||||
r += struct.pack("<I", self.nTime)
|
||||
r += struct.pack("<I", self.nBits)
|
||||
r += struct.pack("<I", self.nNonce)
|
||||
r += ser_uint256(self.nNonce)
|
||||
r += ser_char_vector(self.nSolution)
|
||||
self.sha256 = uint256_from_str(hash256(r))
|
||||
self.hash = hash256(r)[::-1].encode('hex_codec')
|
||||
|
||||
@@ -492,9 +712,9 @@ class CBlockHeader(object):
|
||||
return self.sha256
|
||||
|
||||
def __repr__(self):
|
||||
return "CBlockHeader(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x nTime=%s nBits=%08x nNonce=%08x)" \
|
||||
% (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot,
|
||||
time.ctime(self.nTime), self.nBits, self.nNonce)
|
||||
return "CBlockHeader(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x hashReserved=%064x nTime=%s nBits=%08x nNonce=%064x nSolution=%s)" \
|
||||
% (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot, self.hashReserved,
|
||||
time.ctime(self.nTime), self.nBits, self.nNonce, repr(self.nSolution))
|
||||
|
||||
|
||||
class CBlock(CBlockHeader):
|
||||
@@ -525,7 +745,13 @@ class CBlock(CBlockHeader):
|
||||
hashes = newhashes
|
||||
return uint256_from_str(hashes[0])
|
||||
|
||||
def is_valid(self):
|
||||
def is_valid(self, n=48, k=5):
|
||||
# H(I||...
|
||||
digest = blake2b(digest_size=(512/n)*n/8, person=zcash_person(n, k))
|
||||
digest.update(super(CBlock, self).serialize()[:108])
|
||||
hash_nonce(digest, self.nNonce)
|
||||
if not gbp_validate(self.nSolution, digest, n, k):
|
||||
return False
|
||||
self.calc_sha256()
|
||||
target = uint256_from_compact(self.nBits)
|
||||
if self.sha256 > target:
|
||||
@@ -537,17 +763,31 @@ class CBlock(CBlockHeader):
|
||||
return False
|
||||
return True
|
||||
|
||||
def solve(self):
|
||||
self.calc_sha256()
|
||||
def solve(self, n=48, k=5):
|
||||
target = uint256_from_compact(self.nBits)
|
||||
while self.sha256 > target:
|
||||
# H(I||...
|
||||
digest = blake2b(digest_size=(512/n)*n/8, person=zcash_person(n, k))
|
||||
digest.update(super(CBlock, self).serialize()[:108])
|
||||
self.nNonce = 0
|
||||
while True:
|
||||
# H(I||V||...
|
||||
curr_digest = digest.copy()
|
||||
hash_nonce(curr_digest, self.nNonce)
|
||||
# (x_1, x_2, ...) = A(I, V, n, k)
|
||||
solns = gbp_basic(curr_digest, n, k)
|
||||
for soln in solns:
|
||||
assert(gbp_validate(curr_digest, soln, n, k))
|
||||
self.nSolution = soln
|
||||
self.rehash()
|
||||
if self.sha256 <= target:
|
||||
return
|
||||
self.nNonce += 1
|
||||
self.rehash()
|
||||
|
||||
def __repr__(self):
|
||||
return "CBlock(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x nTime=%s nBits=%08x nNonce=%08x vtx=%s)" \
|
||||
return "CBlock(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x hashReserved=%064x nTime=%s nBits=%08x nNonce=%064x nSolution=%s vtx=%s)" \
|
||||
% (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot,
|
||||
time.ctime(self.nTime), self.nBits, self.nNonce, repr(self.vtx))
|
||||
self.hashReserved, time.ctime(self.nTime), self.nBits,
|
||||
self.nNonce, repr(self.nSolution), repr(self.vtx))
|
||||
|
||||
|
||||
class CUnsignedAlert(object):
|
||||
@@ -629,8 +869,12 @@ class CAlert(object):
|
||||
class msg_version(object):
|
||||
command = "version"
|
||||
|
||||
def __init__(self):
|
||||
self.nVersion = MY_VERSION
|
||||
def __init__(self, overwintered=False):
|
||||
if overwintered:
|
||||
self.nVersion = OVERWINTER_PROTO_VERSION
|
||||
else:
|
||||
self.nVersion = MY_VERSION
|
||||
|
||||
self.nServices = 1
|
||||
self.nTime = time.time()
|
||||
self.addrTo = CAddress()
|
||||
@@ -1082,12 +1326,12 @@ class NodeConn(asyncore.dispatcher):
|
||||
"mempool": msg_mempool
|
||||
}
|
||||
MAGIC_BYTES = {
|
||||
"mainnet": "\xf9\xbe\xb4\xd9", # mainnet
|
||||
"testnet3": "\x0b\x11\x09\x07", # testnet3
|
||||
"regtest": "\xfa\xbf\xb5\xda" # regtest
|
||||
"mainnet": "\x24\xe9\x27\x64", # mainnet
|
||||
"testnet3": "\xfa\x1a\xf9\xbf", # testnet3
|
||||
"regtest": "\xaa\xe8\x3f\x5f" # regtest
|
||||
}
|
||||
|
||||
def __init__(self, dstaddr, dstport, rpc, callback, net="regtest"):
|
||||
def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", overwintered=False):
|
||||
asyncore.dispatcher.__init__(self, map=mininode_socket_map)
|
||||
self.log = logging.getLogger("NodeConn(%s:%d)" % (dstaddr, dstport))
|
||||
self.dstaddr = dstaddr
|
||||
@@ -1104,7 +1348,7 @@ class NodeConn(asyncore.dispatcher):
|
||||
self.disconnect = False
|
||||
|
||||
# stuff version msg into sendbuf
|
||||
vt = msg_version()
|
||||
vt = msg_version(overwintered)
|
||||
vt.addrTo.ip = self.dstaddr
|
||||
vt.addrTo.port = self.dstport
|
||||
vt.addrFrom.ip = "0.0.0.0"
|
||||
|
||||
@@ -24,10 +24,10 @@ if sys.version > '3':
|
||||
bchr = lambda x: bytes([x])
|
||||
bord = lambda x: x
|
||||
|
||||
import copy
|
||||
import struct
|
||||
import binascii
|
||||
|
||||
import test_framework.bignum
|
||||
from test_framework import bignum
|
||||
|
||||
MAX_SCRIPT_SIZE = 10000
|
||||
MAX_SCRIPT_ELEMENT_SIZE = 520
|
||||
@@ -666,7 +666,7 @@ class CScript(bytes):
|
||||
else:
|
||||
other = CScriptOp.encode_op_pushdata(bignum.bn2vch(other))
|
||||
elif isinstance(other, (bytes, bytearray)):
|
||||
other = CScriptOp.encode_op_pushdata(other)
|
||||
other = bytes(CScriptOp.encode_op_pushdata(other))
|
||||
return other
|
||||
|
||||
def __add__(self, other):
|
||||
|
||||
@@ -13,8 +13,11 @@ import shutil
|
||||
import tempfile
|
||||
import traceback
|
||||
|
||||
from authproxy import AuthServiceProxy, JSONRPCException
|
||||
from util import *
|
||||
from authproxy import JSONRPCException
|
||||
from util import assert_equal, check_json_precision, \
|
||||
initialize_chain, initialize_chain_clean, \
|
||||
start_nodes, connect_nodes_bi, stop_nodes, \
|
||||
sync_blocks, sync_mempools, wait_bitcoinds
|
||||
|
||||
|
||||
class BitcoinTestFramework(object):
|
||||
|
||||
@@ -21,8 +21,7 @@ import subprocess
|
||||
import time
|
||||
import re
|
||||
|
||||
from authproxy import AuthServiceProxy, JSONRPCException
|
||||
from util import *
|
||||
from authproxy import AuthServiceProxy
|
||||
|
||||
def p2p_port(n):
|
||||
return 11000 + n + os.getpid()%999
|
||||
@@ -153,7 +152,7 @@ def initialize_chain_clean(test_dir, num_nodes):
|
||||
Useful if a test case wants complete control over initialization.
|
||||
"""
|
||||
for i in range(num_nodes):
|
||||
datadir=initialize_datadir(test_dir, i)
|
||||
initialize_datadir(test_dir, i)
|
||||
|
||||
|
||||
def _rpchost_to_args(rpchost):
|
||||
@@ -214,6 +213,10 @@ def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None):
|
||||
def log_filename(dirname, n_node, logname):
|
||||
return os.path.join(dirname, "node"+str(n_node), "regtest", logname)
|
||||
|
||||
def check_node(i):
|
||||
bitcoind_processes[i].poll()
|
||||
return bitcoind_processes[i].returncode
|
||||
|
||||
def stop_node(node, i):
|
||||
node.stop()
|
||||
bitcoind_processes[i].wait()
|
||||
@@ -369,3 +372,33 @@ def assert_raises(exc, fun, *args, **kwds):
|
||||
raise AssertionError("Unexpected exception raised: "+type(e).__name__)
|
||||
else:
|
||||
raise AssertionError("No exception raised")
|
||||
|
||||
# Returns txid if operation was a success or None
|
||||
def wait_and_assert_operationid_status(node, myopid, in_status='success', in_errormsg=None):
|
||||
print('waiting for async operation {}'.format(myopid))
|
||||
opids = []
|
||||
opids.append(myopid)
|
||||
timeout = 300
|
||||
status = None
|
||||
errormsg = None
|
||||
txid = None
|
||||
for x in xrange(1, timeout):
|
||||
results = node.z_getoperationresult(opids)
|
||||
if len(results)==0:
|
||||
time.sleep(1)
|
||||
else:
|
||||
status = results[0]["status"]
|
||||
if status == "failed":
|
||||
errormsg = results[0]['error']['message']
|
||||
elif status == "success":
|
||||
txid = results[0]['result']['txid']
|
||||
break
|
||||
assert_equal(in_status, status)
|
||||
if errormsg is not None:
|
||||
assert(in_errormsg is not None)
|
||||
assert_equal(in_errormsg in errormsg, True)
|
||||
if os.getenv("PYTHON_DEBUG", ""):
|
||||
print('...returned status: {}'.format(status))
|
||||
if errormsg is not None:
|
||||
print('...returned error: {}'.format(errormsg))
|
||||
return txid
|
||||
|
||||
Reference in New Issue
Block a user