r1
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2014 BitPay Inc.
|
||||
# Copyright 2016-2017 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test framework for agrarian utils.
|
||||
|
||||
Runs automatically during `make check`.
|
||||
|
||||
Can also be run manually."""
|
||||
|
||||
from __future__ import division,print_function,unicode_literals
|
||||
|
||||
import argparse
|
||||
import binascii
|
||||
try:
|
||||
import configparser
|
||||
except ImportError:
|
||||
import ConfigParser as configparser
|
||||
import difflib
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import pprint
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def main():
|
||||
config = configparser.ConfigParser()
|
||||
config.optionxform = str
|
||||
config.read_file(open(os.path.join(os.path.dirname(__file__), "../config.ini"), encoding="utf8"))
|
||||
env_conf = dict(config.items('environment'))
|
||||
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('-v', '--verbose', action='store_true')
|
||||
args = parser.parse_args()
|
||||
verbose = args.verbose
|
||||
|
||||
if verbose:
|
||||
level = logging.DEBUG
|
||||
else:
|
||||
level = logging.ERROR
|
||||
formatter = '%(asctime)s - %(levelname)s - %(message)s'
|
||||
# Add the format/level to the logger
|
||||
logging.basicConfig(format=formatter, level=level)
|
||||
|
||||
bctester(os.path.join(env_conf["SRCDIR"], "test", "util", "data"), "bitcoin-util-test.json", env_conf)
|
||||
|
||||
def bctester(testDir, input_basename, buildenv):
|
||||
""" Loads and parses the input file, runs all tests and reports results"""
|
||||
input_filename = os.path.join(testDir, input_basename)
|
||||
raw_data = open(input_filename, encoding="utf8").read()
|
||||
input_data = json.loads(raw_data)
|
||||
|
||||
failed_testcases = []
|
||||
|
||||
for testObj in input_data:
|
||||
try:
|
||||
bctest(testDir, testObj, buildenv)
|
||||
logging.info("PASSED: " + testObj["description"])
|
||||
except:
|
||||
logging.info("FAILED: " + testObj["description"])
|
||||
failed_testcases.append(testObj["description"])
|
||||
|
||||
if failed_testcases:
|
||||
error_message = "FAILED_TESTCASES:\n"
|
||||
error_message += pprint.pformat(failed_testcases, width=400)
|
||||
logging.error(error_message)
|
||||
sys.exit(1)
|
||||
else:
|
||||
sys.exit(0)
|
||||
|
||||
def bctest(testDir, testObj, buildenv):
|
||||
"""Runs a single test, comparing output and RC to expected output and RC.
|
||||
|
||||
Raises an error if input can't be read, executable fails, or output/RC
|
||||
are not as expected. Error is caught by bctester() and reported.
|
||||
"""
|
||||
# Get the exec names and arguments
|
||||
execprog = os.path.join(buildenv["BUILDDIR"], "src", testObj["exec"] + buildenv["EXEEXT"])
|
||||
execargs = testObj['args']
|
||||
execrun = [execprog] + execargs
|
||||
|
||||
# Read the input data (if there is any)
|
||||
stdinCfg = None
|
||||
inputData = None
|
||||
if "input" in testObj:
|
||||
filename = os.path.join(testDir, testObj["input"])
|
||||
inputData = open(filename, encoding="utf8").read()
|
||||
stdinCfg = subprocess.PIPE
|
||||
|
||||
# Read the expected output data (if there is any)
|
||||
outputFn = None
|
||||
outputData = None
|
||||
outputType = None
|
||||
if "output_cmp" in testObj:
|
||||
outputFn = testObj['output_cmp']
|
||||
outputType = os.path.splitext(outputFn)[1][1:] # output type from file extension (determines how to compare)
|
||||
try:
|
||||
outputData = open(os.path.join(testDir, outputFn), encoding="utf8").read()
|
||||
except:
|
||||
logging.error("Output file " + outputFn + " can not be opened")
|
||||
raise
|
||||
if not outputData:
|
||||
logging.error("Output data missing for " + outputFn)
|
||||
raise Exception
|
||||
if not outputType:
|
||||
logging.error("Output file %s does not have a file extension" % outputFn)
|
||||
raise Exception
|
||||
|
||||
# Run the test
|
||||
proc = subprocess.Popen(execrun, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
|
||||
try:
|
||||
outs = proc.communicate(input=inputData)
|
||||
except OSError:
|
||||
logging.error("OSError, Failed to execute " + execprog)
|
||||
raise
|
||||
|
||||
if outputData:
|
||||
data_mismatch, formatting_mismatch = False, False
|
||||
# Parse command output and expected output
|
||||
try:
|
||||
a_parsed = parse_output(outs[0], outputType)
|
||||
except Exception as e:
|
||||
logging.error('Error parsing command output as %s: %s' % (outputType, e))
|
||||
raise
|
||||
try:
|
||||
b_parsed = parse_output(outputData, outputType)
|
||||
except Exception as e:
|
||||
logging.error('Error parsing expected output %s as %s: %s' % (outputFn, outputType, e))
|
||||
raise
|
||||
# Compare data
|
||||
if a_parsed != b_parsed:
|
||||
logging.error("Output data mismatch for " + outputFn + " (format " + outputType + ")")
|
||||
data_mismatch = True
|
||||
# Compare formatting
|
||||
if outs[0] != outputData:
|
||||
error_message = "Output formatting mismatch for " + outputFn + ":\n"
|
||||
error_message += "".join(difflib.context_diff(outputData.splitlines(True),
|
||||
outs[0].splitlines(True),
|
||||
fromfile=outputFn,
|
||||
tofile="returned"))
|
||||
logging.error(error_message)
|
||||
formatting_mismatch = True
|
||||
|
||||
assert not data_mismatch and not formatting_mismatch
|
||||
|
||||
# Compare the return code to the expected return code
|
||||
wantRC = 0
|
||||
if "return_code" in testObj:
|
||||
wantRC = testObj['return_code']
|
||||
if proc.returncode != wantRC:
|
||||
logging.error("Return code mismatch for " + outputFn)
|
||||
raise Exception
|
||||
|
||||
if "error_txt" in testObj:
|
||||
want_error = testObj["error_txt"]
|
||||
# Compare error text
|
||||
# TODO: ideally, we'd compare the strings exactly and also assert
|
||||
# That stderr is empty if no errors are expected. However, agrarian-tx
|
||||
# emits DISPLAY errors when running as a windows application on
|
||||
# linux through wine. Just assert that the expected error text appears
|
||||
# somewhere in stderr.
|
||||
if want_error not in outs[1]:
|
||||
logging.error("Error mismatch:\n" + "Expected: " + want_error + "\nReceived: " + outs[1].rstrip())
|
||||
raise Exception
|
||||
|
||||
def parse_output(a, fmt):
|
||||
"""Parse the output according to specified format.
|
||||
|
||||
Raise an error if the output can't be parsed."""
|
||||
if fmt == 'json': # json: compare parsed data
|
||||
return json.loads(a)
|
||||
elif fmt == 'hex': # hex: parse and compare binary data
|
||||
return binascii.a2b_hex(a.strip())
|
||||
else:
|
||||
raise NotImplementedError("Don't know how to compare %s" % fmt)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,148 @@
|
||||
[
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-create"],
|
||||
"output_cmp": "blanktxv1.hex",
|
||||
"description": "Creates a blank v1 transaction"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-json","-create", "nversion=1"],
|
||||
"output_cmp": "blanktxv1.json",
|
||||
"description": "Creates a blank v1 transaction (output in json)"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-"],
|
||||
"input": "blanktxv1.hex",
|
||||
"output_cmp": "blanktxv1.hex",
|
||||
"description": "Creates a blank transaction when nothing is piped into agrarian-tx"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-", "delin=1"],
|
||||
"input": "tx394b54bb.hex",
|
||||
"output_cmp": "tt-delin1-out.hex",
|
||||
"description": "Deletes a single input from a transaction"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-json", "-", "delin=1"],
|
||||
"input": "tx394b54bb.hex",
|
||||
"output_cmp": "tt-delin1-out.json",
|
||||
"description": "Deletes a single input from a transaction (output in json)"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-", "delin=31"],
|
||||
"input": "tx394b54bb.hex",
|
||||
"return_code": 1,
|
||||
"error_txt": "error: Invalid TX input index '31'",
|
||||
"description": "Attempts to delete an input with a bad index from a transaction. Expected to fail."
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-", "delout=1"],
|
||||
"input": "tx394b54bb.hex",
|
||||
"output_cmp": "tt-delout1-out.hex",
|
||||
"description": "Deletes a single output from a transaction"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-json", "-", "delout=1"],
|
||||
"input": "tx394b54bb.hex",
|
||||
"output_cmp": "tt-delout1-out.json",
|
||||
"description": "Deletes a single output from a transaction (output in json)"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-", "delout=2"],
|
||||
"input": "tx394b54bb.hex",
|
||||
"return_code": 1,
|
||||
"error_txt": "error: Invalid TX output index '2'",
|
||||
"description": "Attempts to delete an output with a bad index from a transaction. Expected to fail."
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-", "locktime=317000"],
|
||||
"input": "tx394b54bb.hex",
|
||||
"output_cmp": "tt-locktime317000-out.hex",
|
||||
"description": "Adds an nlocktime to a transaction"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-json", "-", "locktime=317000"],
|
||||
"input": "tx394b54bb.hex",
|
||||
"output_cmp": "tt-locktime317000-out.json",
|
||||
"description": "Adds an nlocktime to a transaction (output in json)"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args":
|
||||
["-create",
|
||||
"outaddr=1"],
|
||||
"return_code": 1,
|
||||
"error_txt": "error: TX output missing separator",
|
||||
"description": "Malformed outaddr argument (no address specified). Expected to fail."
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args":
|
||||
["-create",
|
||||
"outaddr=1:DPvuYbbib66zreC6HNNQgUKzF3jnMmxk71:garbage"],
|
||||
"return_code": 1,
|
||||
"error_txt": "error: invalid TX output address",
|
||||
"description": "Malformed outaddr argument (too many separators). Expected to fail."
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args":
|
||||
["-create",
|
||||
"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
|
||||
"in=bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c:18",
|
||||
"in=22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc:1",
|
||||
"outaddr=0.18:DPvuYbbib66zreC6HNNQgUKzF3jnMmxk71",
|
||||
"outaddr=4:D72dLgywmL73JyTwQBfuU29CADz9yCJ99v"],
|
||||
"output_cmp": "txcreate1.hex",
|
||||
"description": "Creates a new transaction with three inputs and two outputs"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args":
|
||||
["-json",
|
||||
"-create",
|
||||
"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
|
||||
"in=bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c:18",
|
||||
"in=22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc:1",
|
||||
"outaddr=0.18:DPvuYbbib66zreC6HNNQgUKzF3jnMmxk71",
|
||||
"outaddr=4:D72dLgywmL73JyTwQBfuU29CADz9yCJ99v"],
|
||||
"output_cmp": "txcreate1.json",
|
||||
"description": "Creates a new transaction with three inputs and two outputs (output in json)"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-create", "outscript=0:"],
|
||||
"output_cmp": "txcreate2.hex",
|
||||
"description": "Creates a new transaction with a single empty output script"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-json", "-create", "outscript=0:"],
|
||||
"output_cmp": "txcreate2.json",
|
||||
"description": "Creates a new transaction with a single empty output script (output in json)"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["01000000000100000000000000000000000000"],
|
||||
"output_cmp": "txcreate2.hex",
|
||||
"description": "Parses a transaction with no inputs and a single output script"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-json", "01000000000100000000000000000000000000"],
|
||||
"output_cmp": "txcreate2.json",
|
||||
"description": "Parses a transaction with no inputs and a single output script (output in json)"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-create", "outscript=0:OP_DROP", "nversion=1"],
|
||||
"output_cmp": "txcreatescript1.hex",
|
||||
"description": "Create a new transaction with a single output script (OP_DROP)"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args": ["-json", "-create", "outscript=0:OP_DROP", "nversion=1"],
|
||||
"output_cmp": "txcreatescript1.json",
|
||||
"description": "Create a new transaction with a single output script (OP_DROP) (output as json)"
|
||||
},
|
||||
{ "exec": "./agrarian-tx",
|
||||
"args":
|
||||
["-create",
|
||||
"in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0",
|
||||
"set=privatekeys:[\"891ns7GR4owBiozmFa8jDSaJWNZ2q4XoSYdUS2kSNuKJ9BaxLkC\"]",
|
||||
"set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\"}]",
|
||||
"sign=ALL",
|
||||
"outaddr=0.001:D72dLgywmL73JyTwQBfuU29CADz9yCJ99v"],
|
||||
"output_cmp": "txcreatesign.hex",
|
||||
"description": "Creates a new transaction with a single input and a single output, and then signs the transaction"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
01000000000000000000
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"txid": "d21633ba23f70118185227be58a63527675641ad37967e2aa461559f577aec43",
|
||||
"version": 1,
|
||||
"size": 10,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
],
|
||||
"vout": [
|
||||
],
|
||||
"hex": "01000000000000000000"
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
01000000031f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff7cca453133921c50d5025878f7f738d1df891fd359763331935784cf6b9c82bf1200000000fffffffffccd319e04a996c96cfc0bf4c07539aa90bd0b1a700ef72fae535d6504f9a6220100000000ffffffff0280a81201000000001976a914ce1c388c454d63b21ebb202010bda79a3b165b4b88ac0084d717000000001976a91414b70d03a3536907a7843f9d9243ddca79d43e3888ac00000000
|
||||
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"txid": "bf8ee16a00913c0bacbf86a75f2c00c595e8048724c9f0db9f09ed71fce3c946",
|
||||
"version": 1,
|
||||
"size": 201,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
},
|
||||
{
|
||||
"txid": "bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c",
|
||||
"vout": 18,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
},
|
||||
{
|
||||
"txid": "22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.18,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 ce1c388c454d63b21ebb202010bda79a3b165b4b OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"hex": "76a914ce1c388c454d63b21ebb202010bda79a3b165b4b88ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkeyhash",
|
||||
"addresses": [
|
||||
"DPvuYbbib66zreC6HNNQgUKzF3jnMmxk71"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 4.00,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 14b70d03a3536907a7843f9d9243ddca79d43e38 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"hex": "76a91414b70d03a3536907a7843f9d9243ddca79d43e3888ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkeyhash",
|
||||
"addresses": [
|
||||
"D72dLgywmL73JyTwQBfuU29CADz9yCJ99v"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"hex": "01000000031f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff7cca453133921c50d5025878f7f738d1df891fd359763331935784cf6b9c82bf1200000000fffffffffccd319e04a996c96cfc0bf4c07539aa90bd0b1a700ef72fae535d6504f9a6220100000000ffffffff0280a81201000000001976a914ce1c388c454d63b21ebb202010bda79a3b165b4b88ac0084d717000000001976a91414b70d03a3536907a7843f9d9243ddca79d43e3888ac00000000"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
01000000000100000000000000000000000000
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"txid": "cf90229625e9eb10f6be8156bf6aa5ec2eca19a42b1e05c11f3029b560a32e13",
|
||||
"version": 1,
|
||||
"size": 19,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "",
|
||||
"hex": "",
|
||||
"type": "nonstandard"
|
||||
}
|
||||
}
|
||||
],
|
||||
"hex": "01000000000100000000000000000000000000"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
0100000000010000000000000000017500000000
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"txid": "f0851b68202f736b792649cfc960259c2374badcb644ab20cac726b5f72f61c9",
|
||||
"version": 1,
|
||||
"size": 20,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DROP",
|
||||
"hex": "75",
|
||||
"type": "nonstandard"
|
||||
}
|
||||
}
|
||||
],
|
||||
"hex": "0100000000010000000000000000017500000000"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d0000000000ffffffff01a0860100000000001976a91414b70d03a3536907a7843f9d9243ddca79d43e3888ac00000000
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"txid": "977e7cd286cb72cd470d539ba6cb48400f8f387d97451d45cdb8819437a303af",
|
||||
"hash": "977e7cd286cb72cd470d539ba6cb48400f8f387d97451d45cdb8819437a303af",
|
||||
"version": 1,
|
||||
"size": 224,
|
||||
"vsize": 224,
|
||||
"weight": 896,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e2[ALL] 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
|
||||
"hex": "48304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e201410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00100000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 5834479edbbe0539b31ffd3a8f8ebadc2165ed01 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"hex": "76a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkeyhash",
|
||||
"addresses": [
|
||||
"193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"hex": "01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008b48304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e201410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000"
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2015-2018 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test share/rpcauth/rpcauth.py
|
||||
"""
|
||||
import base64
|
||||
import configparser
|
||||
import hmac
|
||||
import importlib
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
class TestRPCAuth(unittest.TestCase):
|
||||
def setUp(self):
|
||||
config = configparser.ConfigParser()
|
||||
config_path = os.path.abspath(
|
||||
os.path.join(os.sep, os.path.abspath(os.path.dirname(__file__)),
|
||||
"../config.ini"))
|
||||
with open(config_path, encoding="utf8") as config_file:
|
||||
config.read_file(config_file)
|
||||
sys.path.insert(0, os.path.dirname(config['environment']['RPCAUTH']))
|
||||
self.rpcauth = importlib.import_module('rpcauth')
|
||||
|
||||
def test_generate_salt(self):
|
||||
self.assertLessEqual(len(self.rpcauth.generate_salt()), 32)
|
||||
self.assertGreaterEqual(len(self.rpcauth.generate_salt()), 16)
|
||||
|
||||
def test_generate_password(self):
|
||||
password = self.rpcauth.generate_password()
|
||||
expected_password = base64.urlsafe_b64encode(
|
||||
base64.urlsafe_b64decode(password)).decode('utf-8')
|
||||
self.assertEqual(expected_password, password)
|
||||
|
||||
def test_check_password_hmac(self):
|
||||
salt = self.rpcauth.generate_salt()
|
||||
password = self.rpcauth.generate_password()
|
||||
password_hmac = self.rpcauth.password_to_hmac(salt, password)
|
||||
|
||||
m = hmac.new(bytearray(salt, 'utf-8'),
|
||||
bytearray(password, 'utf-8'), 'SHA256')
|
||||
expected_password_hmac = m.hexdigest()
|
||||
|
||||
self.assertEqual(expected_password_hmac, password_hmac)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user