mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
create_tx and sign_tx create threshold conditions by default if there
are multiple current owners. Created tests
This commit is contained in:
parent
74a1e14183
commit
4c4cae8f81
@ -194,8 +194,8 @@ def create_tx(current_owners, new_owners, inputs, operation, payload=None):
|
||||
conditions = []
|
||||
for fulfillment in fulfillments:
|
||||
if len(new_owners) > 1:
|
||||
condition = ThresholdSha256Fulfillment(threshold=len(new_owners))
|
||||
for new_owner in new_owners:
|
||||
condition = ThresholdSha256Fulfillment(threshold=len(new_owners))
|
||||
condition.add_subfulfillment(Ed25519Fulfillment(public_key=new_owner))
|
||||
elif len(new_owners) == 1:
|
||||
condition = Ed25519Fulfillment(public_key=new_owners[0])
|
||||
@ -231,7 +231,7 @@ def create_tx(current_owners, new_owners, inputs, operation, payload=None):
|
||||
|
||||
|
||||
# TODO: Change sign_tx to populate the fulfillments
|
||||
def sign_tx(transaction, sk):
|
||||
def sign_tx(transaction, sks):
|
||||
"""Sign a transaction
|
||||
|
||||
A transaction signed with the `current_owner` corresponding private key.
|
||||
@ -244,7 +244,20 @@ def sign_tx(transaction, sk):
|
||||
dict: transaction with the `fulfillment` fields populated.
|
||||
|
||||
"""
|
||||
sk = crypto.SigningKey(sk)
|
||||
# validate sk
|
||||
if not isinstance(sks, list):
|
||||
sks = [sks]
|
||||
|
||||
if len(sks) == 1:
|
||||
sk = crypto.SigningKey(sks[0])
|
||||
else:
|
||||
# create a mapping between sk and vk so that we can match the private key to the current_owners
|
||||
key_pairs = {}
|
||||
for sk in sks:
|
||||
signing_key = crypto.SigningKey(sk)
|
||||
vk = signing_key.get_verifying_key().to_ascii().decode()
|
||||
key_pairs[vk] = signing_key
|
||||
|
||||
tx = copy.deepcopy(transaction)
|
||||
|
||||
for fulfillment in tx['transaction']['fulfillments']:
|
||||
@ -254,7 +267,19 @@ def sign_tx(transaction, sk):
|
||||
parsed_fulfillment = Ed25519Fulfillment(public_key=sk.get_verifying_key())
|
||||
else:
|
||||
parsed_fulfillment = Fulfillment.from_json(fulfillment_message['condition']['condition']['details'])
|
||||
parsed_fulfillment.sign(serialize(fulfillment_message), sk)
|
||||
|
||||
# single current owner
|
||||
if isinstance(parsed_fulfillment, Ed25519Fulfillment):
|
||||
parsed_fulfillment.sign(serialize(fulfillment_message), sk)
|
||||
# multiple current owners
|
||||
elif isinstance(parsed_fulfillment, ThresholdSha256Fulfillment):
|
||||
# replace the fulfillments with the signed fulfillments
|
||||
parsed_fulfillment.subconditions = []
|
||||
for current_owner in fulfillment['current_owners']:
|
||||
subfulfillment = get_subcondition_from_vk(fulfillment_message['condition'], current_owner)
|
||||
subfulfillment.sign(serialize(fulfillment_message), key_pairs[current_owner])
|
||||
parsed_fulfillment.add_subfulfillment(subfulfillment)
|
||||
|
||||
signed_fulfillment = parsed_fulfillment.serialize_uri()
|
||||
fulfillment.update({'fulfillment': signed_fulfillment})
|
||||
|
||||
@ -331,10 +356,17 @@ def get_fulfillment_message(transaction, fulfillment):
|
||||
# get previous condition
|
||||
previous_tx = b.get_transaction(fulfillment['input']['txid'])
|
||||
conditions = sorted(previous_tx['transaction']['conditions'], key=lambda d: d['cid'])
|
||||
fulfillment_message['condition'] = conditions[fulfillment['fid']]
|
||||
fulfillment_message['condition'] = conditions[fulfillment['input']['cid']]
|
||||
return fulfillment_message
|
||||
|
||||
|
||||
def get_subcondition_from_vk(condition, vk):
|
||||
threshold_fulfillment = Fulfillment.from_json(condition['condition']['details'])
|
||||
for subcondition in threshold_fulfillment.subconditions:
|
||||
if subcondition['body'].public_key.to_ascii().decode() == vk:
|
||||
return subcondition['body']
|
||||
|
||||
|
||||
def transform_create(tx):
|
||||
"""Change the owner and signature for a ``CREATE`` transaction created by a node"""
|
||||
|
||||
|
@ -745,16 +745,167 @@ class TestBigchainBlock(object):
|
||||
|
||||
|
||||
class TestMultipleInputs(object):
|
||||
def test_transfer_single_owners_single_input(self, b):
|
||||
def test_transfer_single_owners_single_input(self, b, user_sk, user_vk, inputs):
|
||||
# create a new user
|
||||
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||
|
||||
# get inputs
|
||||
owned_inputs = b.get_owned_ids(user_vk)
|
||||
inp = owned_inputs.pop()
|
||||
|
||||
# create a transaction
|
||||
tx = b.create_transaction([user_vk], [user2_sk], inp, 'TRANSFER')
|
||||
tx_signed = b.sign_transaction(tx, user_sk)
|
||||
|
||||
# validate transaction
|
||||
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||
assert len(tx_signed['transaction']['fulfillments']) == 1
|
||||
assert len(tx_signed['transaction']['conditions']) == 1
|
||||
|
||||
def test_transfer_single_owners_multiple_inputs(self, b, user_sk, user_vk):
|
||||
# create a new user
|
||||
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||
|
||||
# create inputs to spend
|
||||
transactions = []
|
||||
for i in range(10):
|
||||
tx = b.create_transaction(b.me, user_vk, None, 'CREATE')
|
||||
tx_signed = b.sign_transaction(tx, b.me_private)
|
||||
transactions.append(tx_signed)
|
||||
b.write_transaction(tx_signed)
|
||||
block = b.create_block(transactions)
|
||||
b.write_block(block, durability='hard')
|
||||
|
||||
# get inputs
|
||||
owned_inputs = b.get_owned_ids(user_vk)
|
||||
inputs = owned_inputs[:3]
|
||||
|
||||
# create a transaction
|
||||
tx = b.create_transaction(user_vk, user2_vk, inputs, 'TRANSFER')
|
||||
tx_signed = b.sign_transaction(tx, user_sk)
|
||||
|
||||
# validate transaction
|
||||
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||
assert len(tx_signed['transaction']['fulfillments']) == 3
|
||||
assert len(tx_signed['transaction']['conditions']) == 3
|
||||
|
||||
def test_transfer_single_owners_single_input_from_multiple_outputs(self, b, user_sk, user_vk):
|
||||
# create a new user
|
||||
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||
|
||||
# create inputs to spend
|
||||
transactions = []
|
||||
for i in range(10):
|
||||
tx = b.create_transaction(b.me, user_vk, None, 'CREATE')
|
||||
tx_signed = b.sign_transaction(tx, b.me_private)
|
||||
transactions.append(tx_signed)
|
||||
b.write_transaction(tx_signed)
|
||||
block = b.create_block(transactions)
|
||||
b.write_block(block, durability='hard')
|
||||
|
||||
# get inputs
|
||||
owned_inputs = b.get_owned_ids(user_vk)
|
||||
inputs = owned_inputs[:3]
|
||||
|
||||
# create a transaction
|
||||
tx = b.create_transaction(user_vk, user2_vk, inputs, 'TRANSFER')
|
||||
tx_signed = b.sign_transaction(tx, user_sk)
|
||||
|
||||
# create block with the transaction
|
||||
block = b.create_block([tx_signed])
|
||||
b.write_block(block, durability='hard')
|
||||
|
||||
# get inputs from user2
|
||||
owned_inputs = b.get_owned_ids(user2_vk)
|
||||
assert len(owned_inputs) == 3
|
||||
|
||||
# create a transaction with a single input from a multiple output transaction
|
||||
inp = owned_inputs.pop()
|
||||
tx = b.create_transaction(user2_vk, user_vk, inp, 'TRANSFER')
|
||||
tx_signed = b.sign_transaction(tx, user2_sk)
|
||||
|
||||
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||
assert len(tx_signed['transaction']['fulfillments']) == 1
|
||||
assert len(tx_signed['transaction']['conditions']) == 1
|
||||
|
||||
def test_single_current_owner_multiple_new_owners_single_input(self, b, user_sk, user_vk, inputs):
|
||||
# create a new users
|
||||
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||
user3_sk, user3_vk = crypto.generate_key_pair()
|
||||
|
||||
# get inputs
|
||||
owned_inputs = b.get_owned_ids(user_vk)
|
||||
inp = owned_inputs.pop()
|
||||
|
||||
# create a transaction
|
||||
tx = b.create_transaction(user_vk, [user2_sk, user3_vk], inp, 'TRANSFER')
|
||||
tx_signed = b.sign_transaction(tx, user_sk)
|
||||
|
||||
# validate transaction
|
||||
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||
assert len(tx_signed['transaction']['fulfillments']) == 1
|
||||
assert len(tx_signed['transaction']['conditions']) == 1
|
||||
|
||||
def test_single_current_owner_multiple_new_owners_multiple_inputs(self, b, user_sk, user_vk):
|
||||
# create a new users
|
||||
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||
user3_sk, user3_vk = crypto.generate_key_pair()
|
||||
|
||||
# create inputs to spend
|
||||
transactions = []
|
||||
for i in range(5):
|
||||
tx = b.create_transaction(b.me, user_vk, None, 'CREATE')
|
||||
tx_signed = b.sign_transaction(tx, b.me_private)
|
||||
transactions.append(tx_signed)
|
||||
b.write_transaction(tx_signed)
|
||||
block = b.create_block(transactions)
|
||||
b.write_block(block, durability='hard')
|
||||
|
||||
# get inputs
|
||||
owned_inputs = b.get_owned_ids(user_vk)
|
||||
inputs = owned_inputs[:3]
|
||||
|
||||
# create a transaction
|
||||
tx = b.create_transaction(user_vk, [user2_vk, user3_vk], inputs, 'TRANSFER')
|
||||
tx_signed = b.sign_transaction(tx, user_sk)
|
||||
|
||||
# validate transaction
|
||||
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||
assert len(tx_signed['transaction']['fulfillments']) == 3
|
||||
assert len(tx_signed['transaction']['conditions']) == 3
|
||||
|
||||
@pytest.mark.skipif(reason='Skip until we fix default threshold signatures')
|
||||
def test_multiple_current_owners_single_new_owner_single_input(self, b, user_sk, user_vk):
|
||||
# create a new users
|
||||
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||
user3_sk, user3_vk = crypto.generate_key_pair()
|
||||
|
||||
# create input to spend
|
||||
tx = b.create_transaction(b.me, [user_vk, user2_vk], None, 'CREATE')
|
||||
tx_signed = b.sign_transaction(tx, b.me_private)
|
||||
block = b.create_block([tx_signed])
|
||||
b.write_block(block, durability='hard')
|
||||
|
||||
# get inputs
|
||||
owned_inputs = b.get_owned_ids(user_vk)
|
||||
inputs = owned_inputs[:3]
|
||||
|
||||
# create a transaction
|
||||
tx = b.create_transaction([user_vk, user2_vk], user3_vk, inputs, 'TRANSFER')
|
||||
tx_signed = b.sign_transaction(tx, [user_sk, user2_sk])
|
||||
|
||||
# validate transaction
|
||||
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||
assert len(tx_signed['transaction']['fulfillments']) == 3
|
||||
assert len(tx_signed['transaction']['conditions']) == 3
|
||||
|
||||
def test_multiple_current_owners_single_new_owner_multiple_inputs(self, b, user_sk, user_vk):
|
||||
pass
|
||||
|
||||
def test_transfer_single_owners_multiple_inputs(self, b):
|
||||
def test_multiple_current_owners_multiple_new_owners_single_input(self, b):
|
||||
pass
|
||||
|
||||
def test_transfer_single_owners_single_input_from_multiple_outputs(self, b):
|
||||
pass
|
||||
|
||||
def test_multiple_owners(self, b):
|
||||
def test_multiple_current_owners_multiple_new_owners_multiple_inputs(self, b):
|
||||
pass
|
||||
|
||||
def test_get_spent(self, b):
|
||||
@ -1033,4 +1184,10 @@ class TestCryptoconditions(object):
|
||||
|
||||
with pytest.raises(exceptions.InvalidSignature):
|
||||
b.validate_transaction(next_tx)
|
||||
assert b.is_valid_transaction(next_tx) == False
|
||||
assert b.is_valid_transaction(next_tx) == False
|
||||
|
||||
def test_default_threshold_signatures_for_multiple_owners(self, b):
|
||||
pass
|
||||
|
||||
def test_get_subcondition_from_vk(self):
|
||||
pass
|
||||
|
Loading…
x
Reference in New Issue
Block a user