pyspool¶
pyspool
is a reference implementation of the Secure Public Online Ownership
Ledger SPOOL and part of the development stack of ascribe.io
Installation¶
pip install pyspool
Contents¶
Overview¶
All hashes are in base 58 so that they can be inserted in the bitcoin blockchain.
Refill Wallet¶
The refill wallet is only used to refill the Federation Wallet with 10000 and 600 satoshi outputs. This way we maintain the Federation Wallet clean which makes it easier to manage.
Federation Wallet¶
The Federation wallet is the wallet from where all the registers in the
blockchain occur. We can check the validity of transactions by looking at the
origin of this transactions and see if the originating address belongs to a
federation. For instance all pieces registered through ascribe.io will
originate from the address 1JttRRdtAi6cDNM23Uq4BEU61R8kJeANJs
for the first
version of the protocol or 1AScRhqdXMrJyxNmjEapMZi1PLFsqmLquG
for protocol
version 01
.
The Federation wallet should only contain fuel outputs with the amount of 10000 satoshi and token outputs with the amount of 600 satoshi. The fuel is used to pay the fee for the transactions and tokens are used to register address on the blockchain.
Ensuring that the Federation wallet cointains outputs with these amounts makes the transactions simpler since there is no need for change. It is also easier to keep track of the unspents in order to prevent invalid transactions due to double spends (specially important when there is a high throughput of transactions).
Examples¶
All the addresses and transaction ids output by this examples can be checked in the bitcoin blockchain.
For this example we will be implementing the following actions:
- Refill Federation wallet with fuel and tokens
user1
registers master editionuser1
registers number of editionsuser1
registers edition number1
user1
transfers edition number1
touser2
user2
consigns edition number1
touser3
user3
unconsigns edition number1
touser2
user2
loans edition number1
touser3
This is the information that we will need:
refill_pass
- refill wallet password
federation_pass
- federation wallet password
user1_pass
user1
passworduser2_pass
user2
passworduser3_pass
user3
passwordrefill_root
('', u'mhyCaF2HFk7CVwKmyQ8TahgVdjnHSr1pTv')
federation_root
('', u'mqXz83H4LCxjf2ie8hYNsTRByvtfV43Pa7')
user1_root
root address for
user1
HD wallet('', u'n36EiKuYYXNS9h84CnkLK3sEevZsfksaGN')
user1_leaf
leaf address for
user1
HD wallet('2015/5/28/9/28/44/982190', u'mjq4rZZEyJGFfzg59RLFmuNJTo3jakEDrS')
user2_leaf
leaf address for
user2
HD wallet('2015/5/28/9/28/45/184623', u'mhRJqLG3BwXXG7YADQD3Ng3c6coZVwoFo6')
user3_leaf
leaf address for
user3
HD wallet('2015/5/28/9/28/45/387493', u'mhMXXntQCorduhcygY7gLdmuunVEM59C8q')
file_hash
file_hash, file_hash + metadata
(u'mhXeWEMLnEwVNnyqKrqUDPAYSuwhfyNXA7', u'mzQxP43Y4A6PfYeArV2mGBEucJfDtsyCk5')
Federation Wallet Refill¶
Before we can start with spool transactions we need to have a Federation with all the necessary fuel and tokens.
>>> from spool import Spool
>>> spool = Spool(testnet=True)
>>> # lets refill the federation wallet with necessary fuel*7 and tokens*11 for this example
>>> txid = spool.refill_main_wallet(refill_root, federation_root[1], 7, 11,
refill_pass, min_confirmations=1, sync=True)
>>> print txid
67d22e66ee46a96e94f08bed0c857f23de39aee8b25db5fa0369c495e072e44c
67d22e66ee46a96e94f08bed0c857f23de39aee8b25db5fa0369c495e072e44c
Registrations¶
user1
registers the master edition¶
Now that we have enough funds in the Federation wallet user1
can ascribe
his master edition. A master edition is a register with edition number 0
that ascribes the piece to user1 making him the original owner/creator of the
piece. Master editions are ascribed to the user’s root address of the HD
wallet.
>>> # user1 registers the master edition of piece with file_hash
>>> txid = spool.register(federation_root, user1_root[1], file_hash,
federation_pass, 0, min_confirmations=1, sync=True)
>>> print txid
f67aa26b5f47e83124040970246c969d04ec9adecc5a97d60754a0f54355ee81
f67aa26b5f47e83124040970246c969d04ec9adecc5a97d60754a0f54355ee81
user1
registers the number of editions¶
Now that user1
has registered the master edition he can now specify how
many editions of the piece will exist. user1
can only do this once and this
cannot be changed in the future. This creates digital scarcity for this
particular piece
>>> # user1 specifies that there will be 10 editions of the piece with hash file_hash
>>> txid = spool.editions(federation_root, user1_root, file_hash,
federation_pass, 10, min_confirmations=1, sync=True)
>>> print txid
f1f2cdf6ef2ee2d8af13f9d45a1fd7700f9f281078c71939f78326a4b6b957dc
f1f2cdf6ef2ee2d8af13f9d45a1fd7700f9f281078c71939f78326a4b6b957dc
user1
registers edition number 1
¶
Once the number of editions is registered user1
can now start registering
editions so that he can transfer ownership to other users. Each edition is
registered to a different leaf address of user1
HD wallet
>>> # user1 registers edition number 1 of piece with file_hash
>>> txid = spool.register(federation_root, user1_leaf[1], file_hash,
federation_pass, 1, min_confirmations=1, sync=True)
>>> print txid
2376a200a326ee7cf87b7fee7ea0f9a80c8b23cc3a0d72732b9a75517e664f23
2376a200a326ee7cf87b7fee7ea0f9a80c8b23cc3a0d72732b9a75517e664f23
Transfers¶
user1
transfers edition number 1
to user2
¶
Now that an edition is registered the user can transfer ownership to another
user. Transfering ownserhip implies a transaction originating from user1
wallet address holding the edition. This means that we need to fuel user1
wallet with the necessary funds before performing a spool transaction
>>> # refill user1 wallet before transfer
>>> txid = spool.refill(federation_root, user1_leaf[1], 1, 1,
federation_pass, min_confirmations=1, sync=True)
>>> print txid
45bc2a3eecac9b5538a3b5bc325e94fcffee47c0025e78ece426aeebfac59c24
>>> # now we can transfer ownserhip of edition 1 from user1 to user2
>>> txid = spool.transfer(user1_leaf, user2_leaf[1], file_hash,
user1_pass, 1, min_confirmations=1, sync=True)
>>> print txid
38509a49b00f3c3c3fadedd2c5ce35ffcc05a9737a36dd1b7ff00ed1ffe5fd80
45bc2a3eecac9b5538a3b5bc325e94fcffee47c0025e78ece426aeebfac59c24 38509a49b00f3c3c3fadedd2c5ce35ffcc05a9737a36dd1b7ff00ed1ffe5fd80
Consignments¶
user2
consigns edition number 1
to user3
¶
user2
now owns edition 1
of piece with hash file_hash
and he can
transfer ownership of the piece. Lets consign the piece to user3
>>> # refill user2 wallet before consign
>>> txid = spool.refill(federation_root, user2_leaf[1], 1, 1,
federation_pass, min_confirmations=1, sync=True)
>>> print txid
e07732c8af3557277f68871babc874766c511fdf898449cc9be9e505f8325f10
>>> # now we can consign edition 1 from user2 to user3
>>> txid = spool.consign(user2_leaf, user3_leaf[1], file_hash,
user2_pass, 1, min_confirmations=1, sync=True)
>>> print txid
3b30cea26d49eb023ccd62fb78ddd9308c9505fe0796abc0fe60989980fc5eb8
e07732c8af3557277f68871babc874766c511fdf898449cc9be9e505f8325f10 3b30cea26d49eb023ccd62fb78ddd9308c9505fe0796abc0fe60989980fc5eb8
Unconsignments¶
user3
unconsigns edition number 1
to user2
¶
Now lets unconsign the piece with hash file_hash
back to user2
>>> # refill user3 wallet before unconsign
>>> txid = spool.refill(federation_root, user3_leaf[1], 1, 1,
federation_pass, min_confirmations=1, sync=True)
>>> print txid
f0c9cf0832e7ca14012e7379da35dd2d50bd66df45c2eb089a23b10db4047dcc
>>> # user3 unconsigns edition number 1 back to user2
>>> txid = spool.unconsign(user3_leaf, user2_leaf[1], file_hash,
user3_pass, 1, min_confirmations=1, sync=True)
>>> print txid
11dcb46061526790e0e7cf0a83e9163d35b75461cd203858c1fd7bdb2149db0c
f0c9cf0832e7ca14012e7379da35dd2d50bd66df45c2eb089a23b10db4047dcc 11dcb46061526790e0e7cf0a83e9163d35b75461cd203858c1fd7bdb2149db0c
Loans¶
user2
loans edition number 1
to user3
¶
Now that user2
owns the edition again lets loan it to user3
from
15-05-22 to 15-05-23
>>> # refill user2 wallet before loan
>>> txid = spool.refill(federation_root, user2_leaf[1], 1, 1,
federation_pass, min_confirmations=1, sync=True)
>>> print txid
087d85fd421db42c3efac5e6aa499edfe7386101b85314b44c86681a98c27832
>>> # user2 loans edition number 1 to user3
>>> txid = spool.loan(user2_leaf, user3_leaf[1], file_hash,
user2_pass, 1, '150522', '150523', min_confirmations=1, sync=True)
>>> print txid
6cc0066ee737a7104859328729cd10f8c5a5b64be3f4f8bfcab04f8a6aca4c56
087d85fd421db42c3efac5e6aa499edfe7386101b85314b44c86681a98c27832 6cc0066ee737a7104859328729cd10f8c5a5b64be3f4f8bfcab04f8a6aca4c56
Library Reference¶
Spool¶
-
class
spool.
Spool
(testnet=False, service=u'blockr', username=u'', password=u'', host=u'', port=u'')¶ Class that contains all Spool methods.
In the SPOOL implementation there is no notion of users only addresses. All addresses come from BIP32 HD wallets. This makes it easier to manage all the keys since we can retrieve everything we need from a master secret (namely the private key to sign the transactions).
Since we are dealing with HD wallets we expect all
from_address
to be a tuple of(path, address)
so that we can retrieve the private key for that particular leaf address. If we want to use the root address we can just pass an empty string to the first element of the tuple e.g.('', address)
. For instance when using the federation wallet address we have no need to create leaf addresses.- A file is represented by two hashes:
file_hash
: is the hash of the digital filefile_hash_metadata
: is the hash of the digital file + metadata
The hash is passed to the methods has a tuple:
(file_hash, file_hash_metadata)
-
FEE
¶ int
transaction fee
-
TOKEN
¶ int
token
-
SPENTS_QUEUE_MAXSIZE
¶ int
spent outputs queue maximum size
-
__init__
(testnet=False, service=u'blockr', username=u'', password=u'', host=u'', port=u'')¶ Parameters: - testnet (bool) – Whether to use the mainnet or testnet.
Defaults to the mainnet (
False
). - service (str) – Bitcoin communication interface:
'blockr'
,'daemon'
, or'regtest'
.'blockr'
refers to the public api, whereas'daemon'
and'regtest'
refer to the jsonrpc inteface. Defaults to'blockr'
. - username (str) – username for jsonrpc communications
- password (str) – password for jsonrpc communications
- hostname (str) – hostname of the bitcoin node when using jsonrpc
- port (str) – port number of the bitcoin node when using jsonrpc
- testnet (bool) – Whether to use the mainnet or testnet.
Defaults to the mainnet (
-
consign
(*args, **kwargs)¶ Consign a piece to an address
Parameters: - from_address (Tuple[str]) – Address currently owning the edition
- to_address (str) – Address to where the piece will be consigned to
- hash (Tuple[str]) – Hash of the piece. Tuple (file_hash, file_hash_metadata)
- password (str) – Password for the wallet currently owning the edition. For signing the transaction
- edition_num (int) – the number of the edition to consign
- min_confirmations (int) – Number of confirmations when chosing the inputs of the transaction. Defaults to 6
- sync (bool) – Perform the transaction in synchronous mode, the call to the function will block until there is at least on confirmation on the blockchain. Defaults to False
- ownership (bool) – Check ownsership in the blockchain before pushing the transaction. Defaults to True
Returns: transaction id
Return type:
-
consigned_registration
(*args, **kwargs)¶ Register an edition or master edition of a piece consigned to
from_address
Parameters: - from_address (Tuple[str]) – Federation address. All register transactions originate from the the Federation wallet
- to_address (str) – Address registering the edition
- hash (Tuple[str]) – Hash of the piece. Tuple (file_hash, file_hash_metadata)
- password (str) – Federation wallet password. For signing the transaction
- min_confirmations (int) – Override the number of confirmations when chosing the inputs of the transaction. Defaults to 6
- sync (bool) – Perform the transaction in synchronous mode, the call to the function will block until there is at least on confirmation on the blockchain. Defaults to False
- ownership (bool) – Check ownsership in the blockchain before pushing the transaction. Defaults to True
Returns: transaction id
Return type:
-
editions
(*args, **kwargs)¶ Register the number of editions of a piece
Parameters: - from_address (Tuple[str]) – Federation address. All register transactions originate from the the Federation wallet
- to_address (str) – Address registering the number of editions
- hash (Tuple[str]) – Hash of the piece. Tuple (file_hash, file_hash_metadata)
- password (str) – Federation wallet password. For signing the transaction
- num_editions (int) – Number of editions of the piece
- min_confirmations (int) – Number of confirmations when chosing the inputs of the transaction. Defaults to 6
- sync (bool) – Perform the transaction in synchronous mode, the call to the function will block until there is at least on confirmation on the blockchain. Defaults to False
- ownership (bool) – Check ownsership in the blockchain before pushing the transaction. Defaults to True
Returns: transaction id
Return type:
-
loan
(*args, **kwargs)¶ Loan the edition
Parameters: - from_address (Tuple[str]) – Address currently holding the edition
- to_address (str) – Address to loan the edition to
- hash (Tuple[str]) – Hash of the piece. Tuple (file_hash, file_hash_metadata)
- password (str) – Password for the wallet currently holding the edition. For signing the transaction
- edition_num (int) – the number of the edition to loan
- loan_start (str) – Start date for the loan. In the form YYMMDD
- loan_end (str) – End date for the loan. In the form YYMMDD
- min_confirmations (int) – Number of confirmations when chosing the inputs of the transaction. Defaults to 6
- sync (bool) – Perform the transaction in synchronous mode, the call to the function will block until there is at least on confirmation on the blockchain. Defaults to False
- ownership (bool) – Check ownsership in the blockchain before pushing the transaction. Defaults to True
Returns: transaction id
Return type:
-
migrate
(*args, **kwargs)¶ Migrate an edition
Parameters: - from_address (Tuple[str]) – Federation address. All register transactions originate from the the Federation wallet
- to_address (str) – Address registering the edition
- hash (Tuple[str]) – Hash of the piece. Tuple (file_hash, file_hash_metadata)
- password (str) – Federation wallet password. For signing the transaction
- edition_num (int) – The number of the edition to register. User edition_num=0 to register the master edition
- min_confirmations (int) – Override the number of confirmations when chosing the inputs of the transaction. Defaults to 6
- sync (bool) – Perform the transaction in synchronous mode, the call to the function will block until there is at least on confirmation on the blockchain. Defaults to False
- ownership (bool) – Check ownsership in the blockchain before pushing the transaction. Defaults to True
Returns: transaction id
Return type:
-
refill
(*args, **kwargs)¶ Refill wallets with the necessary fuel to perform spool transactions
Parameters: - from_address (Tuple[str]) – Federation wallet address. Fuels the wallets with tokens and fees. All transactions to wallets holding a particular piece should come from the Federation wallet
- to_address (str) – Wallet address that needs to perform a spool transaction
- nfees (int) – Number of fees to transfer. Each fee is 10000 satoshi. Used to pay for the transactions
- ntokens (int) – Number of tokens to transfer. Each token is 600 satoshi. Used to register hashes in the blockchain
- password (str) – Password for the Federation wallet. Used to sign the transaction
- min_confirmations (int) – Number of confirmations when chosing the inputs of the transaction. Defaults to 6
- sync (bool) – Perform the transaction in synchronous mode, the call to the function will block until there is at least on confirmation on the blockchain. Defaults to False
Returns: transaction id
Return type:
-
refill_main_wallet
(*args, **kwargs)¶ Refill the Federation wallet with tokens and fees. This keeps the federation wallet clean. Dealing with exact values simplifies the transactions. No need to calculate change. Easier to keep track of the unspents and prevent double spends that would result in transactions being rejected by the bitcoin network.
Parameters: - from_address (Tuple[str]) – Refill wallet address. Refills the federation wallet with tokens and fees
- to_address (str) – Federation wallet address
- nfees (int) – Number of fees to transfer. Each fee is 10000 satoshi. Used to pay for the transactions
- ntokens (int) – Number of tokens to transfer. Each token is 600 satoshi. Used to register hashes in the blockchain
- password (str) – Password for the Refill wallet. Used to sign the transaction
- min_confirmations (int) – Number of confirmations when chosing the inputs of the transaction. Defaults to 6
- sync (bool) – Perform the transaction in synchronous mode, the call to the function will block until there is at least on confirmation on the blockchain. Defaults to False
Returns: transaction id
Return type:
-
register
(*args, **kwargs)¶ Register an edition or master edition of a piece
Parameters: - from_address (Tuple[str]) – Federation address. All register transactions originate from the the Federation wallet
- to_address (str) – Address registering the edition
- hash (Tuple[str]) – Hash of the piece. Tuple (file_hash, file_hash_metadata)
- password (str) – Federation wallet password. For signing the transaction
- edition_num (int) – The number of the edition to register. User edition_num=0 to register the master edition
- min_confirmations (int) – Override the number of confirmations when chosing the inputs of the transaction. Defaults to 6
- sync (bool) – Perform the transaction in synchronous mode, the call to the function will block until there is at least on confirmation on the blockchain. Defaults to False
- ownership (bool) – Check ownsership in the blockchain before pushing the transaction. Defaults to True
Returns: transaction id
Return type:
-
register_piece
(*args, **kwargs)¶ Register a piece
Parameters: - from_address (Tuple[str]) – Federation address. All register transactions originate from the the Federation wallet
- to_address (str) – Address registering the edition
- hash (Tuple[str]) – Hash of the piece. (file_hash, file_hash_metadata)
- password (str) – Federation wallet password. For signing the transaction
- edition_num (int) – The number of the edition to register. User edition_num=0 to register the master edition
- min_confirmations (int) – Override the number of confirmations when chosing the inputs of the transaction. Defaults to 6
- sync (bool) – Perform the transaction in synchronous mode, the call to the function will block until there is at least on confirmation on the blockchain. Defaults to False
- ownership (bool) – Check ownsership in the blockchain before pushing the transaction. Defaults to True
Returns: transaction id
Return type:
-
select_inputs
(address, nfees, ntokens, min_confirmations=6)¶ Selects the inputs for the spool transaction.
Parameters:
-
simple_spool_transaction
(from_address, to, op_return, min_confirmations=6)¶ Utililty function to create the spool transactions. Selects the inputs, encodes the op_return and constructs the transaction.
Parameters: - from_address (str) – Address originating the transaction
- to (str) – list of addresses to receive tokens (file_hash, file_hash_metadata, ...)
- op_return (str) – String representation of the spoolverb, as returned by the properties of Spoolverb
- min_confirmations (int) – Number of confirmations when chosing the inputs of the transaction. Defaults to 6
Returns: unsigned transaction
Return type:
-
transfer
(*args, **kwargs)¶ Transfer a piece between addresses
Parameters: - from_address (Tuple[str]) – Address currently owning the edition
- to_address – Address to receive the edition
- hash (Tuple[str]) – Hash of the piece. Tuple (file_hash, file_hash_metadata)
- password (str) – Password for the wallet currently owning the edition. For signing the transaction
- edition_num (int) – the number of the edition to transfer
- min_confirmations (int) – Number of confirmations when chosing the inputs of the transaction. Defaults to 6
- sync (bool) – Perform the transaction in synchronous mode, the call to the function will block until there is at least on confirmation on the blockchain. Defaults to False
- ownership (bool) – Check ownsership in the blockchain before pushing the transaction. Defaults to True
Returns: transaction id
Return type:
-
unconsign
(*args, **kwargs)¶ Unconsign the edition
Parameters: - from_address (Tuple[str]) – Address where the edition is currently consigned
- to_address (str) – Address that consigned the piece to from_address
- hash (Tuple[str]) – Hash of the piece. Tuple (file_hash, file_hash_metadata)
- password (str) – Password for the wallet currently holding the edition. For signing the transaction
- edition_num (int) – the number of the edition to unconsign
- min_confirmations (int) – Number of confirmations when chosing the inputs of the transaction. Defaults to 6
- sync (bool) – Perform the transaction in synchronous mode, the call to the function will block until there is at least on confirmation on the blockchain. Defaults to False
- ownership (bool) – Check ownsership in the blockchain before pushing the transaction. Defaults to True
Returns: transaction id
Return type:
File¶
-
class
spool.
File
(filename, testnet=False, **kwargs)¶ Class used to calculate the hash of a file and the hash of the file + metadata to be included on the blockchain
-
__init__
(filename, testnet=False, **kwargs)¶ Parameters: - filename (str) – Name of the file
- testnet (bool) – testnet flag. Defaults to False
- **kwargs –
Additional metadata to be encoded with the file. Only the values are used to compute the hash. Values are ordered using their keys, so that the computation of the hash is consistent. As an example, given:
File('filename', title='piece title', artist='artist')
the values
('artist', 'piece title')
would be used in that order for the computation of the hash.
Returns: File
instance
-
Wallet¶
-
class
spool.
Wallet
(password, testnet=False)¶ Represents a BIP32 wallet.
-
wallet
¶ BIP32Node
BIP32NOde
instance.
-
root_address
¶ Tuple[str]
Root address of the HD Wallet.
-
__init__
(password, testnet=False)¶ Initializes a BIP32 wallet.
Addresses returned by the wallet are of the form
(path, address)
.Parameters:
-
Spoolverb¶
-
class
spool.
Spoolverb
(num_editions=None, edition_num=None, loan_start=u'', loan_end=u'', meta=u'ASCRIBESPOOL', version=u'01', action=None)¶ Allows for easy creation of the verb to be encoded on the
op_return
of all SPOOL transactions.-
supported_actions
¶ List[str]
Actions supported by the SPOOL protocol.
-
__init__
(num_editions=None, edition_num=None, loan_start=u'', loan_end=u'', meta=u'ASCRIBESPOOL', version=u'01', action=None)¶ Initializer for the Spoolverb class.
Parameters: - num_editions (int) – Number of editions to register.
- edition_num (str) – Number of the edition to use.
- loan_start (str) – Start of the loan in the format
YYMMDD
. - loan_end (str) – End of the loan in the format
YYMMDD
. - meta (str) – Header for the spool protocol. Defaults to
'ASCRIBESPOOL'
. - version (str) – Version of the protocol. Defaults to
'01'
. - action (str) – One of the actions in
supported_actions
.
Returns: Spoolverb
instance.
-
consign
¶ - str: representation of the
CONSIGN
spoolverb. E.g.: 'ASCRIBESPOOL01CONSIGN1'
.
- str: representation of the
-
consigned_registration
¶ - str: representation of the
CONSIGNEDREGISTRATION
spoolverb. E.g.: 'ASCRIBESPOOL01CONSIGNEDREGISTRATION'
.
- str: representation of the
-
editions
¶ - str: representation of the
EDITIONS
spoolverb. E.g.: 'ASCRIBESPOOL01EDITIONS10'
.
- str: representation of the
-
classmethod
from_verb
(verb)¶ Constructs a
Spoolverb
instance from the string representation of the given verb.Parameters: verb (str) – representation of the verb e.g.: 'ASCRIBESPOOL01LOAN12/150526150528'
. Can also be in binary format (bytes
):b'ASCRIBESPOOL01PIECE'
.Returns: Spoolverb
instance.
-
fuel
¶ - str: representation of the
FUEL
spoolverb. E.g.: 'ASCRIBESPOOL01FUEL'
.
- str: representation of the
-
loan
¶ - str: representation of the
LOAN
spoolverb. E.g.: 'ASCRIBESPOOL01LOAN1/150526150528'
.
- str: representation of the
-
migrate
¶ - str: representation of the
MIGRATE
spoolverb. E.g.: 'ASCRIBESPOOL01MIGRATE1'
.
- str: representation of the
-
piece
¶ - str: representation of the
PIECE
spoolverb. E.g.: 'ASCRIBESPOOL01PIECE'
.
- str: representation of the
-
register
¶ - str: representation of the
REGISTER
spoolverb. E.g.: 'ASCRIBESPOOL01REGISTER1'`
.
- str: representation of the
-
transfer
¶ - str: representation of the
TRANSFER
spoolverb. E.g.: 'ASCRIBESPOOL01TRANSFER1'
.
- str: representation of the
-
unconsign
¶ - str: representation of the
UNCONSIGN
spoolverb. E.g.: 'ASCRIBESPOOL01UNCONSIGN1'
.
- str: representation of the
-
BlockchainSpider¶
-
class
spool.
BlockchainSpider
(testnet=False, service=u'blockr', username=u'', password=u'', host=u'', port=u'')¶ Spool blockchain explorer. Retrieves from the blockchain the chain of ownership of a hash created with the SPOOL protocol.
-
__init__
(testnet=False, service=u'blockr', username=u'', password=u'', host=u'', port=u'')¶ Parameters: - testnet (bool) – Whether to use the mainnet or testnet.
Defaults to the mainnet (
False
). - service (str) – Bitcoin communication interface:
'blockr'
,'daemon'
, or'regtest'
.'blockr'
refers to the public api, whereas'daemon'
and'regtest'
refer to the jsonrpc inteface. Defaults to'blockr'
. - username (str) – username for jsonrpc communications
- password (str) – password for jsonrpc communications
- hostname (str) – hostname of the bitcoin node when using jsonrpc
- port (str) – port number of the bitcoin node when using jsonrpc
- testnet (bool) – Whether to use the mainnet or testnet.
Defaults to the mainnet (
-
static
chain
(tree, edition_number)¶ Parameters: Returns: The chain of ownsership of a particular edition of the piece ordered by time.
Return type:
-
static
check_script
(vouts)¶ Looks into the vouts list of a transaction and returns the
op_return
if one exists.- Args;
- vouts (list): List of outputs of a transaction.
Returns: String representation of the op_return
.Return type: str Raises: Exception
– If novout
having a supported verb (supported_actions
) is found.
-
static
decode_op_return
(op_return_hex)¶ Decodes the given
op_return
hexadecimal string representation into a string (str
).Parameters: op_return_hex (str) – Hexadecimal string representation of the op_return
.Returns: String representation of the op_return
.Return type: str
-
history
(hash)¶ Retrieve the ownership tree of all editions of a piece given the hash.
Parameters: hash (str) – Hash of the file to check. Can be created with the File
classReturns: Ownsership tree of all editions of a piece. Return type: dict Note
For now we only support searching the blockchain by the piece hash.
-
Ownership¶
-
class
spool.
Ownership
(address, piece_address, edition_number, testnet=False, service=u'blockr', username=u'', password=u'', host=u'', port=u'')¶ Checks the actions that an address can make on a piece.
-
address
¶ str
Bitcoin address to check ownership over
piece_address
.
-
piece_address
¶ str
Bitcoin address of the piece to check.
-
edition_number
¶ int
The edition number of the piece.
-
testnet
¶ bool
Bitcoin network.
True
fortestnet
orFalse
formainnet
.
-
reason
¶ str
Message indicating the reason for the failure of an ownership property.
-
__init__
(address, piece_address, edition_number, testnet=False, service=u'blockr', username=u'', password=u'', host=u'', port=u'')¶ Parameters: - address (str) – Bitcoin address to check ownership over
piece_address
. - piece_address (str) – Bitcoin address of the piece to check.
- edition_number (int) – The edition number of the piece.
- testnet (Optional[boo]l) – Whether to use the testnet
(
True
) or the mainnet (False
). Defaults toFalse
. - service (Optional[str]) – Name of service to use to connect
to the bitcoin network. Possible names are
('blockr', 'daemon', 'regtest')
. Defaults to'blockr'
. - username (Optional[str]) – Username to connect to a bitcoin node
via json-rpc based services:
('daemon', 'regtest')
. - password (Optional[str]) – Password to connect to a bitcoin node
via json-rpc based services:
('daemon', 'regtest').
- host (Optional[str]) – Host of the bitcoin node to connect to
via json-rpc based services:
('daemon', 'regtest')
. - port (Optional[str]) – Port of the bitcoin node to connect to
via json-rpc based services:
('daemon', 'regtest')
.
- address (str) – Bitcoin address to check ownership over
-
can_consign
¶ bool:
True
ifaddress
can consign the editionedition_number
ofpiece_address
elseFalse
.
-
can_editions
¶ bool:
True
ifaddress
can register the number of editions ofpiece_address
elseFalse
.In order to register the number of editions:
1. There needs to a least one transaction for the
piece_address
(the registration of the master edition).2. A piece with address
piece_address
needs to be registered with'ASCRIBESPOOL01PIECE'
(master edition).3. The number of editions should have not been set yet (no tx with verb
'ASCRIBESPOOLEDITIONS'
).
-
can_loan
¶ bool:
True
ifaddress
can loan the editionedition_number
ofpiece_address
elseFalse
.
-
can_register
¶ bool:
True
ifaddress
can register the editionedition_number
ofpiece_address
elseFalse
.In order to register an edition:
- The master piece needs to be registered.
- The number of editions needs to be registered.
- The
edition_number
should not have been registered yet.
Todo
Also check that the root address owns the piece. Right now we cannot do this because we only receive the leaf address when registering an edition.
-
can_register_master
¶ bool:
True
ifaddress
can register the master edition ofpiece_address
elseFalse
.To register a master edition the piece address cannot exist in the bitcoin network.
-
can_transfer
¶ bool:
True
ifaddress
can transfer the editionedition_number
ofpiece_address
elseFalse
.
-
can_unconsign
¶ bool:
True
ifaddress
can unconsign the editionedition_number
ofpiece_address
elseFalse
.If the last transaction is a consignment of the edition to the user.
-
Exceptions¶
-
class
spool.ownership.
OwnershipError
(message)¶ To be raised when an address does not have ownership of a hash
-
message
¶ str
Message of the exception.
-
-
class
spool.spool.
SpoolFundsError
(message)¶ To be raised when an address does not have ownership of a hash.
-
message
¶ str
Message of the exception.
-
Testing¶
At the moment most tests rely on a bitcoin regtest node running. Depending on how the bitcoin node is run some environment variables may need to be set.
The simplest is to use the provided docker-compose.yml under the
pyspool
github repository.
First run the bitcoin regtest daemon in background mode:
$ docker-compose up -d bitcoin
Then run the tests:
$ docker-compose run --rm spool py.test -v
To run the tests against python 2:
$ docker-compose run --rm spool-py2 py.test -v
Note
You may need to build the image for the services spool
and
spool-py2
. E.g.:
$ docker-compose build spool
Without Docker¶
The tests rely on four environment variables specific to bitcoin:
-
BITCOIN_HOST
¶ The host of the bitcoin regtest node. Defaults to
'localhost'
.
-
BITCOIN_PORT
¶ The port of the bitcoin regtest node. Defaults to
18332
.
-
BITCOIN_RPCUSER
¶ The rpc user used to connect to bitcoin regtest node. Defaults to
'merlin'
.
-
BITCOIN_RPCPASSWORD
¶ The password of the user, used to connect to the bitcoin regtest node. Defaults to
'secret'
.
Assuming the above default environment variables, a bitcoin regtest node can be run as follows:
$ bitcoind -daemon -regtest -rpcuser=merlin -rpcpassword=secret -txindex=1
Important
Please note the -txindex=1
option. This ensures that all
transactions are indexed and retrievable by the RPC
getrawtransaction
. Without this option some tests will fail.
Using a bitcoin.conf
¶
A bitcoin.conf file can also be used. E.g.:
# $HOME/.bitcoin/bitcoin.conf (under linux)
rpcuser=merlin
rpcpassword=secret
txindex=1
Tip
The .travis.yml, docker-compose.yml, and bitcoin_regtest.conf
files, under the pyspool
github repository may be helpful to look at.
Contributing¶
Pull requests, feedback, and suggestions are welcome. Github repository is at https://github.com/ascribe/pyspool
You can also send inquiries directly to devel@ascribe.io
About this Documentation¶
This section contains instructions to build and view the documentation locally,
using the docker-compose.yml
file of the pyspool
repository:
https://github.com/ascribe/pyspool.
If you do not have a clone of the repo, you need to get one.
Building the documentation¶
To build the docs, simply run
$ docker-compose up bdocs
Or if you prefer, start a bash
session,
$ docker-compose run --rm bdocs bash
and build the docs:
root@a651959a1f2d:/usr/src/app/docs# make html
Viewing the documentation¶
You can start a little web server to view the docs at http://localhost:40084/
$ docker-compose up -d vdocs
Note
If you are using docker-machine
you need to replace localhost
with the ip
of the machine (e.g.: docker-machine ip tm
if your
machine is named tm
).
Making changes¶
The necessary source code is mounted, which allows you to make modifications, and view the changes by simply re-building the docs, and refreshing the browser.
Background¶
pyspool was developed by ascribe GmbH as part of the overall ascribe technology stack. http://www.ascribe.io
License¶
Licensed under the Apache License, Version 2.0.