mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Refactor sign_tx. Fix tests
The implicit condition of create transactions is now handled by `get_fulfillment_message` instead of `sign_tx`
This commit is contained in:
parent
cbb9a55de8
commit
a4bbffa544
@ -28,4 +28,5 @@ class DatabaseDoesNotExist(Exception):
|
||||
class KeypairNotFoundException(Exception):
|
||||
"""Raised if operation cannot proceed because the keypair was not given"""
|
||||
|
||||
|
||||
class KeypairMismatchException(Exception):
|
||||
"""Raised if the private key(s) provided for signing don't match any of the curret owner(s)"""
|
||||
|
@ -248,9 +248,6 @@ def sign_tx(transaction, sks):
|
||||
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:
|
||||
@ -262,22 +259,27 @@ def sign_tx(transaction, sks):
|
||||
|
||||
for fulfillment in tx['transaction']['fulfillments']:
|
||||
fulfillment_message = get_fulfillment_message(transaction, fulfillment)
|
||||
if tx['transaction']['operation'] in ['CREATE', 'GENESIS']:
|
||||
# sign the fulfillment message
|
||||
parsed_fulfillment = Ed25519Fulfillment(public_key=sk.get_verifying_key())
|
||||
else:
|
||||
parsed_fulfillment = Fulfillment.from_json(fulfillment_message['condition']['condition']['details'])
|
||||
|
||||
# single current owner
|
||||
if isinstance(parsed_fulfillment, Ed25519Fulfillment):
|
||||
parsed_fulfillment.sign(serialize(fulfillment_message), sk)
|
||||
current_owner = fulfillment['current_owners'][0]
|
||||
try:
|
||||
parsed_fulfillment.sign(serialize(fulfillment_message), key_pairs[current_owner])
|
||||
except KeyError:
|
||||
raise exceptions.KeypairMismatchException('Public key {} is not a pair to any of the private keys'
|
||||
.format(current_owner))
|
||||
# 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)
|
||||
try:
|
||||
subfulfillment.sign(serialize(fulfillment_message), key_pairs[current_owner])
|
||||
except KeyError:
|
||||
raise exceptions.KeypairMismatchException('Public key {} is not a pair to any of the private keys'
|
||||
.format(current_owner))
|
||||
parsed_fulfillment.add_subfulfillment(subfulfillment)
|
||||
|
||||
signed_fulfillment = parsed_fulfillment.serialize_uri()
|
||||
@ -351,12 +353,18 @@ def get_fulfillment_message(transaction, fulfillment):
|
||||
'condition': None,
|
||||
})
|
||||
|
||||
# if not a `CREATE` transaction
|
||||
# if `TRANSFER` transaction
|
||||
if fulfillment['input']:
|
||||
# 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['input']['cid']]
|
||||
# if `CREATE` transaction
|
||||
# there is no previous transaction so we need to create one on the fly
|
||||
else:
|
||||
current_owner = transaction['transaction']['fulfillments'][0]['current_owners'][0]
|
||||
condition = json.loads(Ed25519Fulfillment(public_key=current_owner).serialize_json())
|
||||
fulfillment_message['condition'] = {'condition': {'details': condition}}
|
||||
return fulfillment_message
|
||||
|
||||
|
||||
|
@ -41,7 +41,7 @@ class TestBigchainApi(object):
|
||||
input_tx = b.get_owned_ids(user_vk).pop()
|
||||
assert b.verify_signature(b.get_transaction(input_tx['txid'])) == True
|
||||
|
||||
tx = b.create_transaction(b.me, user_sk, input_tx, 'TRANSFER')
|
||||
tx = b.create_transaction(user_vk, b.me, input_tx, 'TRANSFER')
|
||||
|
||||
assert sorted(tx) == sorted(['id', 'transaction', 'version'])
|
||||
assert sorted(tx['transaction']) == sorted(['conditions', 'data', 'fulfillments', 'operation', 'timestamp'])
|
||||
@ -260,14 +260,6 @@ class TestTransactionValidation(object):
|
||||
assert excinfo.value.args[0] == 'Only federation nodes can use the operation `CREATE`'
|
||||
assert b.is_valid_transaction(tx) is False
|
||||
|
||||
tx_signed = b.sign_transaction(tx, b.me_private)
|
||||
|
||||
with pytest.raises(exceptions.OperationError) as excinfo:
|
||||
b.validate_transaction(tx_signed)
|
||||
|
||||
assert excinfo.value.args[0] == 'Only federation nodes can use the operation `CREATE`'
|
||||
assert b.is_valid_transaction(tx_signed) is False
|
||||
|
||||
def test_non_create_operation_no_inputs(self, b, user_vk):
|
||||
tx = b.create_transaction(user_vk, user_vk, None, 'TRANSFER')
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@ -326,16 +318,25 @@ class TestTransactionValidation(object):
|
||||
assert b.is_valid_transaction(tx_valid) is False
|
||||
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
def test_wrong_signature(self, b, user_vk):
|
||||
def test_wrong_signature(self, b, user_sk, user_vk):
|
||||
input_valid = b.get_owned_ids(user_vk).pop()
|
||||
tx_valid = b.create_transaction(user_vk, user_vk, input_valid, 'TRANSFER')
|
||||
|
||||
wrong_private_key = '4fyvJe1aw2qHZ4UNRYftXK7JU7zy9bCqoU5ps6Ne3xrY'
|
||||
|
||||
with pytest.raises(exceptions.KeypairMismatchException):
|
||||
tx_invalid_signed = b.sign_transaction(tx_valid, wrong_private_key)
|
||||
|
||||
# create a correctly signed transaction and change the signature
|
||||
tx_signed = b.sign_transaction(tx_valid, user_sk)
|
||||
fulfillment = tx_signed['transaction']['fulfillments'][0]['fulfillment']
|
||||
changed_fulfillment = Ed25519Fulfillment().from_uri(fulfillment)
|
||||
changed_fulfillment.signature = b'0' * 64
|
||||
tx_signed['transaction']['fulfillments'][0]['fulfillment'] = changed_fulfillment.serialize_uri()
|
||||
|
||||
with pytest.raises(exceptions.InvalidSignature):
|
||||
b.validate_transaction(tx_invalid_signed)
|
||||
assert b.is_valid_transaction(tx_invalid_signed) is False
|
||||
b.validate_transaction(tx_signed)
|
||||
assert b.is_valid_transaction(tx_signed) is False
|
||||
|
||||
def test_valid_create_transaction(self, b, user_vk):
|
||||
tx = b.create_transaction(b.me, user_vk, None, 'CREATE')
|
||||
|
Loading…
x
Reference in New Issue
Block a user