diff options
| -rw-r--r-- | .travis.yml | 1 | ||||
| -rwxr-xr-x | qa/pull-tester/install-deps.sh | 10 | ||||
| -rwxr-xr-x | qa/pull-tester/rpc-tests.sh | 1 | ||||
| -rwxr-xr-x | qa/rpc-tests/auxpow.py | 80 | ||||
| -rw-r--r-- | qa/rpc-tests/test_framework/scrypt_auxpow.py | 105 |
5 files changed, 197 insertions, 0 deletions
diff --git a/.travis.yml b/.travis.yml index 4a0c792fa..33b473ff4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -85,6 +85,7 @@ matrix: before_script: - unset CC; unset CXX - mkdir -p depends/SDKs depends/sdk-sources + - if [ "$RUN_TESTS" = "true" ]; then qa/pull-tester/install-deps.sh; fi - if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then wget $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -O depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS diff --git a/qa/pull-tester/install-deps.sh b/qa/pull-tester/install-deps.sh new file mode 100755 index 000000000..3941031bc --- /dev/null +++ b/qa/pull-tester/install-deps.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# installs test dependencies + +wget https://pypi.python.org/packages/source/l/ltc_scrypt/ltc_scrypt-1.0.tar.gz +#echo "7d019c3c98f16eb466a272e518ffb014 ltc_scrypt-1.0.tar.gz" | md5sum -c +tar zxf ltc_scrypt-1.0.tar.gz +pushd ltc_scrypt-1.0 +python setup.py install --user +popd diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index f7aa15015..750ffc3ce 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -16,6 +16,7 @@ fi #Run the tests testScripts=( + 'auxpow.py' 'wallet.py' 'listtransactions.py' 'mempool_resurrect_test.py' diff --git a/qa/rpc-tests/auxpow.py b/qa/rpc-tests/auxpow.py new file mode 100755 index 000000000..e194a217c --- /dev/null +++ b/qa/rpc-tests/auxpow.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015 The Dogecoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test AuxPOW RPC interface and constraints +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from struct import * +import binascii +import json +import StringIO +from test_framework import scrypt_auxpow + +class AuxPOWTest (BitcoinTestFramework): + REWARD = 500000 # reward per block + CHAIN_ID = "62" + DIGISHIELD_START = 10 # nHeight when digishield starts + AUXPOW_START = 20 # nHeight when auxpow starts + MATURITY_HEIGHT = 60 # number of blocks for mined transactions to mature + + def setup_chain(self): + print("Initializing test directory " + self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 2) + + def setup_network(self, split=False): + self.nodes = start_nodes(2, self.options.tmpdir) + connect_nodes_bi(self.nodes,0,1) + self.is_network_split=False + self.sync_all() + + def run_test(self): + print "Mining blocks..." + + # 1. mine an auxpow block before auxpow is allowed, expect: fail + scrypt_auxpow.mineScryptAux(self.nodes[0], "00", True) + self.sync_all() + + # 2. mine a non-auxpow block, just to ensure that this node + # can mine at all, expect: success + self.nodes[0].generate(1) + self.sync_all() + + # 3. mine blocks until we're in digishield era + self.nodes[1].generate(self.DIGISHIELD_START - 1 - 1) + self.sync_all() + + # 4. mine an auxpow block before auxpow is allowed, attempt 2 + # expect: fail + scrypt_auxpow.mineScryptAux(self.nodes[0], "00", True) + self.sync_all() + + # 5. mine blocks until we're in in auxpow era + self.nodes[1].generate(self.AUXPOW_START - self.DIGISHIELD_START) + self.sync_all() + + # 6. mine a valid auxpow block, expect: success + scrypt_auxpow.mineScryptAux(self.nodes[0], "00", True) + + # 7. mine an auxpow block with high pow, expect: fail + scrypt_auxpow.mineScryptAux(self.nodes[0], "00", False) + + # 8. mine a valid auxpow block with the parent chain being us + # expect: fail + scrypt_auxpow.mineScryptAux(self.nodes[0], self.CHAIN_ID, True) + self.sync_all() + + # 9. mine enough blocks to mature all node 0 rewards + self.nodes[1].generate(self.MATURITY_HEIGHT) + self.sync_all() + + # node 0 should have block rewards for 2 blocks, + # One from step 2 and one from step 6. + assert_equal(self.nodes[0].getbalance(), self.REWARD * 2) + +if __name__ == '__main__': + AuxPOWTest ().main () diff --git a/qa/rpc-tests/test_framework/scrypt_auxpow.py b/qa/rpc-tests/test_framework/scrypt_auxpow.py new file mode 100644 index 000000000..0d85062a9 --- /dev/null +++ b/qa/rpc-tests/test_framework/scrypt_auxpow.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# Copyright (c) 2014 Daniel Kraft +# Copyright (c) 2015 The Dogecoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# General code for scrypt auxpow testing. This includes routines to +# solve an auxpow header and to generate auxpow blocks with scrypt. +# extends and modifies auxpow module by Daniel Kraft. + +# This module requires a built and installed version of the ltc_scrypt +# package, which can be downloaded from: +# https://pypi.python.org/packages/source/l/ltc_scrypt/ltc_scrypt-1.0.tar.gz + +import binascii +import hashlib +import auxpow +import ltc_scrypt + +def computeAuxpowWithChainId (block, target, chainid, ok): + """ + Build an auxpow object (serialised as hex string) that solves the + block, for a given chain id. + """ + + # Start by building the merge-mining coinbase. The merkle tree + # consists only of the block hash as root. + coinbase = "fabe" + binascii.hexlify ("m" * 2) + coinbase += block + coinbase += "01000000" + ("00" * 4) + + # Construct "vector" of transaction inputs. + vin = "01" + vin += ("00" * 32) + ("ff" * 4) + vin += ("%02x" % (len (coinbase) / 2)) + coinbase + vin += ("ff" * 4) + + # Build up the full coinbase transaction. It consists only + # of the input and has no outputs. + tx = "01000000" + vin + "00" + ("00" * 4) + txHash = auxpow.doubleHashHex (tx) + + # Construct the parent block header. It need not be valid, just good + # enough for auxpow purposes. + header = "0100" + chainid + "00" + header += "00" * 32 + header += auxpow.reverseHex (txHash) + header += "00" * 4 + header += "00" * 4 + header += "00" * 4 + + # Mine the block. + (header, blockhash) = mineScryptBlock (header, target, ok) + + # Build the MerkleTx part of the auxpow. + output = tx + output += blockhash + output += "00" + output += "00" * 4 + + # Extend to full auxpow. + output += "00" + output += "00" * 4 + output += header + + return output + +# for now, just offer hashes to rpc until it matches the work we need +def mineScryptAux (node, chainid, ok): + """ + Mine an auxpow block on the given RPC connection. + """ + + auxblock = node.getauxblock () + target = auxpow.reverseHex (auxblock['_target']) + + apow = computeAuxpowWithChainId (auxblock['hash'], target, chainid, ok) + res = node.getauxblock (auxblock['hash'], apow) + +def mineScryptBlock (header, target, ok): + """ + Given a block header, update the nonce until it is ok (or not) + for the given target. + """ + + data = bytearray (binascii.unhexlify (header)) + while True: + assert data[79] < 255 + data[79] += 1 + hexData = binascii.hexlify (data) + + scrypt = getScryptPoW(hexData) + if (ok and scrypt < target) or ((not ok) and scrypt > target): + break + + blockhash = auxpow.doubleHashHex (hexData) + return (hexData, blockhash) + +def getScryptPoW(hexData): + """ + Actual scrypt pow calculation + """ + + data = binascii.unhexlify(hexData) + return auxpow.reverseHex(binascii.hexlify(ltc_scrypt.getPoWHash(data))) |