mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Moved consensus package files into single consensus.py module
This commit is contained in:
parent
9644df07f7
commit
01d706ac56
152
bigchaindb/consensus.py
Normal file
152
bigchaindb/consensus.py
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
import bigchaindb.exceptions as exceptions
|
||||||
|
from bigchaindb import util
|
||||||
|
from bigchaindb.crypto import hash_data
|
||||||
|
|
||||||
|
# TODO: no real reason to use abc yet, but later we can enforce inheritance from
|
||||||
|
# this class when loading plugins if that's desirable.
|
||||||
|
# from abc import ABCMeta
|
||||||
|
|
||||||
|
class AbstractConsensusRules:
|
||||||
|
|
||||||
|
# TODO: rather than having plugin-authors inherit and override,
|
||||||
|
# it'd be cleaner to make a `transactionrule` decorator and etc
|
||||||
|
@classmethod
|
||||||
|
def validate_transaction(cls, bigchain, transaction):
|
||||||
|
"""Validate a transaction.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bigchain (Bigchain): an instantiated bigchaindb.Bigchain object.
|
||||||
|
transaction (dict): transaction to validate.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The transaction if the transaction is valid else it raises an
|
||||||
|
exception describing the reason why the transaction is invalid.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
Descriptive exceptions indicating the reason the transaction failed.
|
||||||
|
See the `exceptions` module for bigchain-native error classes.
|
||||||
|
"""
|
||||||
|
return transaction
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validate_block(cls, bigchain, block):
|
||||||
|
"""Validate a block.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bigchain (Bigchain): an instantiated bigchaindb.Bigchain object.
|
||||||
|
block (dict): block to validate.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The block if the block is valid else it raises and exception
|
||||||
|
describing the reason why the block is invalid.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
Descriptive exceptions indicating the reason the block failed.
|
||||||
|
See the `exceptions` module for bigchain-native error classes.
|
||||||
|
"""
|
||||||
|
return block
|
||||||
|
|
||||||
|
class ConsensusRules(AbstractConsensusRules):
|
||||||
|
"""Base consensus rules for Bigchain.
|
||||||
|
|
||||||
|
This class can be copied to write your own consensus rules!
|
||||||
|
|
||||||
|
Note: Consensus plugins will be executed in the order that they're listed in
|
||||||
|
the bigchain config file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validate_transaction(cls, bigchain, transaction):
|
||||||
|
"""Validate a transaction.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bigchain (Bigchain): an instantiated bigchaindb.Bigchain object.
|
||||||
|
transaction (dict): transaction to validate.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The transaction if the transaction is valid else it raises an
|
||||||
|
exception describing the reason why the transaction is invalid.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
OperationError: if the transaction operation is not supported
|
||||||
|
TransactionDoesNotExist: if the input of the transaction is not found
|
||||||
|
TransactionOwnerError: if the new transaction is using an input it doesn't own
|
||||||
|
DoubleSpend: if the transaction is a double spend
|
||||||
|
InvalidHash: if the hash of the transaction is wrong
|
||||||
|
InvalidSignature: if the signature of the transaction is wrong
|
||||||
|
"""
|
||||||
|
|
||||||
|
# If the operation is CREATE the transaction should have no inputs and
|
||||||
|
# should be signed by a federation node
|
||||||
|
if transaction['transaction']['operation'] == 'CREATE':
|
||||||
|
if transaction['transaction']['input']:
|
||||||
|
raise ValueError('A CREATE operation has no inputs')
|
||||||
|
if transaction['transaction']['current_owner'] not in (
|
||||||
|
bigchain.federation_nodes + [bigchain.me]):
|
||||||
|
raise exceptions.OperationError(
|
||||||
|
'Only federation nodes can use the operation `CREATE`')
|
||||||
|
|
||||||
|
else:
|
||||||
|
# check if the input exists, is owned by the current_owner
|
||||||
|
if not transaction['transaction']['input']:
|
||||||
|
raise ValueError(
|
||||||
|
'Only `CREATE` transactions can have null inputs')
|
||||||
|
|
||||||
|
tx_input = bigchain.get_transaction(
|
||||||
|
transaction['transaction']['input'])
|
||||||
|
|
||||||
|
if not tx_input:
|
||||||
|
raise exceptions.TransactionDoesNotExist(
|
||||||
|
'input `{}` does not exist in the bigchain'.format(
|
||||||
|
transaction['transaction']['input']))
|
||||||
|
|
||||||
|
if (tx_input['transaction']['new_owner'] !=
|
||||||
|
transaction['transaction']['current_owner']):
|
||||||
|
raise exceptions.TransactionOwnerError(
|
||||||
|
'current_owner `{}` does not own the input `{}`'.format(
|
||||||
|
transaction['transaction']['current_owner'],
|
||||||
|
transaction['transaction']['input']))
|
||||||
|
|
||||||
|
# check if the input was already spent by a transaction other than
|
||||||
|
# this one.
|
||||||
|
spent = bigchain.get_spent(tx_input['id'])
|
||||||
|
if spent and spent['id'] != transaction['id']:
|
||||||
|
raise exceptions.DoubleSpend(
|
||||||
|
'input `{}` was already spent'.format(
|
||||||
|
transaction['transaction']['input']))
|
||||||
|
|
||||||
|
# Check hash of the transaction
|
||||||
|
calculated_hash = hash_data(util.serialize(
|
||||||
|
transaction['transaction']))
|
||||||
|
if calculated_hash != transaction['id']:
|
||||||
|
raise exceptions.InvalidHash()
|
||||||
|
|
||||||
|
# Check signature
|
||||||
|
if not bigchain.verify_signature(transaction):
|
||||||
|
raise exceptions.InvalidSignature()
|
||||||
|
|
||||||
|
return transaction
|
||||||
|
|
||||||
|
# TODO: check that the votings structure is correctly constructed
|
||||||
|
@classmethod
|
||||||
|
def validate_block(cls, bigchain, block):
|
||||||
|
"""Validate a block.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bigchain (Bigchain): an instantiated bigchaindb.Bigchain object.
|
||||||
|
block (dict): block to validate.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The block if the block is valid else it raises and exception
|
||||||
|
describing the reason why the block is invalid.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
InvalidHash: if the hash of the block is wrong.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Check if current hash is correct
|
||||||
|
calculated_hash = hash_data(util.serialize(block['block']))
|
||||||
|
if calculated_hash != block['id']:
|
||||||
|
raise exceptions.InvalidHash()
|
||||||
|
|
||||||
|
return block
|
@ -1,43 +0,0 @@
|
|||||||
# TODO: no real reason to use abc yet, but later we can enforce inheritance from
|
|
||||||
# this class when loading plugins if that's desirable.
|
|
||||||
# from abc import ABCMeta
|
|
||||||
|
|
||||||
class AbstractConsensusRules:
|
|
||||||
|
|
||||||
# TODO: rather than having plugin-authors inherit and override,
|
|
||||||
# it'd be cleaner to make a `transactionrule` decorator and etc
|
|
||||||
@classmethod
|
|
||||||
def validate_transaction(cls, bigchain, transaction):
|
|
||||||
"""Validate a transaction.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
bigchain (Bigchain): an instantiated bigchaindb.Bigchain object.
|
|
||||||
transaction (dict): transaction to validate.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The transaction if the transaction is valid else it raises an
|
|
||||||
exception describing the reason why the transaction is invalid.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
Descriptive exceptions indicating the reason the transaction failed.
|
|
||||||
See the `exceptions` module for bigchain-native error classes.
|
|
||||||
"""
|
|
||||||
return transaction
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def validate_block(cls, bigchain, block):
|
|
||||||
"""Validate a block.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
bigchain (Bigchain): an instantiated bigchaindb.Bigchain object.
|
|
||||||
block (dict): block to validate.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The block if the block is valid else it raises and exception
|
|
||||||
describing the reason why the block is invalid.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
Descriptive exceptions indicating the reason the block failed.
|
|
||||||
See the `exceptions` module for bigchain-native error classes.
|
|
||||||
"""
|
|
||||||
return block
|
|
@ -1,109 +0,0 @@
|
|||||||
import bigchaindb.exceptions as exceptions
|
|
||||||
from bigchaindb import util
|
|
||||||
from bigchaindb.crypto import hash_data
|
|
||||||
from bigchaindb.consensus import AbstractConsensusRules
|
|
||||||
|
|
||||||
class ConsensusRules(AbstractConsensusRules):
|
|
||||||
"""Base consensus rules for Bigchain.
|
|
||||||
|
|
||||||
This class can be copied to write your own consensus rules!
|
|
||||||
|
|
||||||
Note: Consensus plugins will be executed in the order that they're listed in
|
|
||||||
the bigchain config file.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def validate_transaction(cls, bigchain, transaction):
|
|
||||||
"""Validate a transaction.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
bigchain (Bigchain): an instantiated bigchaindb.Bigchain object.
|
|
||||||
transaction (dict): transaction to validate.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The transaction if the transaction is valid else it raises an
|
|
||||||
exception describing the reason why the transaction is invalid.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
OperationError: if the transaction operation is not supported
|
|
||||||
TransactionDoesNotExist: if the input of the transaction is not found
|
|
||||||
TransactionOwnerError: if the new transaction is using an input it doesn't own
|
|
||||||
DoubleSpend: if the transaction is a double spend
|
|
||||||
InvalidHash: if the hash of the transaction is wrong
|
|
||||||
InvalidSignature: if the signature of the transaction is wrong
|
|
||||||
"""
|
|
||||||
|
|
||||||
# If the operation is CREATE the transaction should have no inputs and
|
|
||||||
# should be signed by a federation node
|
|
||||||
if transaction['transaction']['operation'] == 'CREATE':
|
|
||||||
if transaction['transaction']['input']:
|
|
||||||
raise ValueError('A CREATE operation has no inputs')
|
|
||||||
if transaction['transaction']['current_owner'] not in (
|
|
||||||
bigchain.federation_nodes + [bigchain.me]):
|
|
||||||
raise exceptions.OperationError(
|
|
||||||
'Only federation nodes can use the operation `CREATE`')
|
|
||||||
|
|
||||||
else:
|
|
||||||
# check if the input exists, is owned by the current_owner
|
|
||||||
if not transaction['transaction']['input']:
|
|
||||||
raise ValueError(
|
|
||||||
'Only `CREATE` transactions can have null inputs')
|
|
||||||
|
|
||||||
tx_input = bigchain.get_transaction(
|
|
||||||
transaction['transaction']['input'])
|
|
||||||
|
|
||||||
if not tx_input:
|
|
||||||
raise exceptions.TransactionDoesNotExist(
|
|
||||||
'input `{}` does not exist in the bigchain'.format(
|
|
||||||
transaction['transaction']['input']))
|
|
||||||
|
|
||||||
if (tx_input['transaction']['new_owner'] !=
|
|
||||||
transaction['transaction']['current_owner']):
|
|
||||||
raise exceptions.TransactionOwnerError(
|
|
||||||
'current_owner `{}` does not own the input `{}`'.format(
|
|
||||||
transaction['transaction']['current_owner'],
|
|
||||||
transaction['transaction']['input']))
|
|
||||||
|
|
||||||
# check if the input was already spent by a transaction other than
|
|
||||||
# this one.
|
|
||||||
spent = bigchain.get_spent(tx_input['id'])
|
|
||||||
if spent and spent['id'] != transaction['id']:
|
|
||||||
raise exceptions.DoubleSpend(
|
|
||||||
'input `{}` was already spent'.format(
|
|
||||||
transaction['transaction']['input']))
|
|
||||||
|
|
||||||
# Check hash of the transaction
|
|
||||||
calculated_hash = hash_data(util.serialize(
|
|
||||||
transaction['transaction']))
|
|
||||||
if calculated_hash != transaction['id']:
|
|
||||||
raise exceptions.InvalidHash()
|
|
||||||
|
|
||||||
# Check signature
|
|
||||||
if not bigchain.verify_signature(transaction):
|
|
||||||
raise exceptions.InvalidSignature()
|
|
||||||
|
|
||||||
return transaction
|
|
||||||
|
|
||||||
# TODO: check that the votings structure is correctly constructed
|
|
||||||
@classmethod
|
|
||||||
def validate_block(cls, bigchain, block):
|
|
||||||
"""Validate a block.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
bigchain (Bigchain): an instantiated bigchaindb.Bigchain object.
|
|
||||||
block (dict): block to validate.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The block if the block is valid else it raises and exception
|
|
||||||
describing the reason why the block is invalid.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
InvalidHash: if the hash of the block is wrong.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Check if current hash is correct
|
|
||||||
calculated_hash = hash_data(util.serialize(block['block']))
|
|
||||||
if calculated_hash != block['id']:
|
|
||||||
raise exceptions.InvalidHash()
|
|
||||||
|
|
||||||
return block
|
|
@ -1,21 +0,0 @@
|
|||||||
import bigchaindb.exceptions as exceptions
|
|
||||||
from bigchaindb.crypto import hash_data
|
|
||||||
from bigchaindb.consensus import AbstractConsensusRules
|
|
||||||
|
|
||||||
|
|
||||||
class SillyConsensusRules(AbstractConsensusRules):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def validate_transaction(cls, bigchain, transaction):
|
|
||||||
# I only like transactions whose timestamps are even.
|
|
||||||
if transaction['transaction']['timestamp'] % 2 != 0:
|
|
||||||
raise StandardError("Odd... very odd indeed.")
|
|
||||||
return transaction
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def validate_block(cls, bigchain, transaction):
|
|
||||||
# I don't trust Alice, I think she's shady.
|
|
||||||
if block['block']['node_pubkey'] == '<ALICE_PUBKEY>':
|
|
||||||
raise StandardError("Alice is shady, everybody ignore her blocks!")
|
|
||||||
|
|
||||||
return block
|
|
Loading…
x
Reference in New Issue
Block a user