Skip to content
Snippets Groups Projects
Commit db1640ac authored by Fabian Schuh's avatar Fabian Schuh
Browse files

[bitshares] propose and bundle transaction

parent b2252da1
No related branches found
No related tags found
No related merge requests found
...@@ -33,8 +33,11 @@ class BitShares(object): ...@@ -33,8 +33,11 @@ class BitShares(object):
:param str rpcpassword: RPC password *(optional)* :param str rpcpassword: RPC password *(optional)*
:param bool nobroadcast: Do **not** broadcast a transaction! *(optional)* :param bool nobroadcast: Do **not** broadcast a transaction! *(optional)*
:param bool debug: Enable Debugging *(optional)* :param bool debug: Enable Debugging *(optional)*
:param array,dict,string keys: Predefine the wif keys to shortcut the wallet database :param array,dict,string keys: Predefine the wif keys to shortcut the wallet database *(optional)*
:param bool offline: Boolean to prevent connecting to network (defaults to ``False``) :param bool offline: Boolean to prevent connecting to network (defaults to ``False``) *(optional)*
:param str proposer: Propose a transaction using this proposer *(optional)*
:param int expiration: Delay in seconds until transactions are supposed to expire *(optional)*
:param bool bundle: Do not broadcast transactions right away, but allow to bundle operations *(optional)*
Three wallet operation modes are possible: Three wallet operation modes are possible:
...@@ -106,11 +109,12 @@ class BitShares(object): ...@@ -106,11 +109,12 @@ class BitShares(object):
self.rpc = None self.rpc = None
self.debug = debug self.debug = debug
self.offline = kwargs.get("offline", False) self.offline = bool(kwargs.get("offline", False))
self.nobroadcast = kwargs.get("nobroadcast", False) self.nobroadcast = bool(kwargs.get("nobroadcast", False))
self.unsigned = kwargs.get("unsigned", False) self.unsigned = bool(kwargs.get("unsigned", False))
self.expiration = int(kwargs.get("expiration", 30)) self.expiration = int(kwargs.get("expiration", 30))
self.proposer = kwargs.get("proposer", None) self.proposer = kwargs.get("proposer", None)
self.bundle = bool(kwargs.get("bundle", False))
if not self.offline: if not self.offline:
self._connect(node=node, self._connect(node=node,
...@@ -119,6 +123,7 @@ class BitShares(object): ...@@ -119,6 +123,7 @@ class BitShares(object):
**kwargs) **kwargs)
self.wallet = Wallet(self.rpc, **kwargs) self.wallet = Wallet(self.rpc, **kwargs)
self.txbuffer = TransactionBuilder(bitshares_instance=self)
def _connect(self, def _connect(self,
node="", node="",
...@@ -169,19 +174,23 @@ class BitShares(object): ...@@ -169,19 +174,23 @@ class BitShares(object):
posting permission. Neither can you use different posting permission. Neither can you use different
accounts for different operations! accounts for different operations!
""" """
tx = TransactionBuilder(bitshares_instance=self) # Append transaction
tx.appendOps(ops) self.txbuffer.appendOps(ops)
if self.unsigned: if self.unsigned:
tx.addSigningInformation(account, permission) # In case we don't want to sign anything
return tx self.txbuffer.addSigningInformation(account, permission)
return self.txbuffer
elif self.bundle:
# In case we want to add more ops to the tx (bundle)
self.txbuffer.appendSigner(account, permission)
else: else:
tx.appendSigner(account, permission) # default behavior: sign + broadcast
tx.sign() self.txbuffer.appendSigner(account, permission)
self.txbuffer.sign()
return self.txbuffer.broadcast()
return tx.broadcast() def sign(self, tx=None, wifs=[]):
def sign(self, tx, wifs=[]):
""" Sign a provided transaction witht he provided key(s) """ Sign a provided transaction witht he provided key(s)
:param dict tx: The transaction to be signed and returned :param dict tx: The transaction to be signed and returned
...@@ -190,18 +199,25 @@ class BitShares(object): ...@@ -190,18 +199,25 @@ class BitShares(object):
from the wallet as defined in "missing_signatures" key from the wallet as defined in "missing_signatures" key
of the transactions. of the transactions.
""" """
tx = TransactionBuilder(tx, bitshares_instance=self) if tx:
tx.appendMissingSignatures(wifs) txbuffer = TransactionBuilder(tx, bitshares_instance=self)
tx.sign() else:
return tx.json() txbuffer = self.txbuffer
txbuffer.appendWif(wifs)
txbuffer.appendMissingSignatures()
txbuffer.sign()
return txbuffer.json()
def broadcast(self, tx): def broadcast(self, tx=None):
""" Broadcast a transaction to the BitShares network """ Broadcast a transaction to the BitShares network
:param tx tx: Signed transaction to broadcast :param tx tx: Signed transaction to broadcast
""" """
tx = TransactionBuilder(tx) if tx:
return tx.broadcast() # If tx is provided, we broadcast the tx
return TransactionBuilder(tx).broadcast()
else:
return self.txbuffer.broadcast()
def info(self): def info(self):
""" Returns the global properties """ Returns the global properties
......
...@@ -31,10 +31,9 @@ class TransactionBuilder(dict): ...@@ -31,10 +31,9 @@ class TransactionBuilder(dict):
:param list ops: One or a list of operations :param list ops: One or a list of operations
""" """
if isinstance(ops, list): if isinstance(ops, list):
for op in ops: self.ops.extend(ops)
self.op.append(op)
else: else:
self.op.append(ops) self.ops.append(ops)
def appendSigner(self, account, permission): def appendSigner(self, account, permission):
""" Try to obtain the wif key from the wallet by telling which account """ Try to obtain the wif key from the wallet by telling which account
...@@ -66,7 +65,7 @@ class TransactionBuilder(dict): ...@@ -66,7 +65,7 @@ class TransactionBuilder(dict):
def appendWif(self, wif): def appendWif(self, wif):
""" Add a wif that should be used for signing of the transaction. """ Add a wif that should be used for signing of the transaction.
""" """
if wif: if wif:
try: try:
PrivateKey(wif) PrivateKey(wif)
...@@ -79,7 +78,7 @@ class TransactionBuilder(dict): ...@@ -79,7 +78,7 @@ class TransactionBuilder(dict):
store store
""" """
if self.bitshares.proposer: if self.bitshares.proposer:
ops = [operations.Op_wrapper(op=o) for o in list(self.op)] ops = [operations.Op_wrapper(op=o) for o in list(self.ops)]
proposer = Account( proposer = Account(
self.bitshares.proposer, self.bitshares.proposer,
bitshares_instance=self.bitshares bitshares_instance=self.bitshares
...@@ -94,7 +93,7 @@ class TransactionBuilder(dict): ...@@ -94,7 +93,7 @@ class TransactionBuilder(dict):
}) })
ops = [Operation(ops)] ops = [Operation(ops)]
else: else:
ops = [Operation(o) for o in list(self.op)] ops = [Operation(o) for o in list(self.ops)]
ops = transactions.addRequiredFees(self.bitshares.rpc, ops) ops = transactions.addRequiredFees(self.bitshares.rpc, ops)
expiration = transactions.formatTimeFromNow(self.bitshares.expiration) expiration = transactions.formatTimeFromNow(self.bitshares.expiration)
...@@ -170,13 +169,16 @@ class TransactionBuilder(dict): ...@@ -170,13 +169,16 @@ class TransactionBuilder(dict):
except Exception as e: except Exception as e:
raise e raise e
self.clear()
return self return self
def clear(self): def clear(self):
""" Clear the transaction builder and start from scratch """ Clear the transaction builder and start from scratch
""" """
self.op = [] self.ops = []
self.wifs = [] self.wifs = []
super(TransactionBuilder, self).__init__({})
def addSigningInformation(self, account, permission): def addSigningInformation(self, account, permission):
""" This is a private method that adds side information to a """ This is a private method that adds side information to a
...@@ -214,7 +216,7 @@ class TransactionBuilder(dict): ...@@ -214,7 +216,7 @@ class TransactionBuilder(dict):
""" """
return dict(self) return dict(self)
def appendMissingSignatures(self, wifs=[]): def appendMissingSignatures(self):
""" Store which accounts/keys are supposed to sign the transaction """ Store which accounts/keys are supposed to sign the transaction
This method is used for an offline-signer! This method is used for an offline-signer!
......
********* *********
Tutorials Tutorials
********* *********
Bundle Many Operations
----------------------
With BitShares, you can bundle multiple operations into a single
transactions. This can be used to do a multi-send (one sender, multiple
receivers), but it also allows to use any other kind of operation. The
advantage here is that the user can be sure that the operations are
executed in the same order as they are added to the transaction.
.. code-block:: python
from pprint import pprint
from bitshares import BitShares
testnet = BitShares(
"wss://node.testnet.bitshares.eu",
nobroadcast=True,
bundle=True,
)
testnet.wallet.unlock("supersecret")
testnet.transfer("init0", 1, "TEST", account="xeroc")
testnet.transfer("init1", 1, "TEST", account="xeroc")
testnet.transfer("init2", 1, "TEST", account="xeroc")
testnet.transfer("init3", 1, "TEST", account="xeroc")
pprint(testnet.broadcast())
Proposing a Transaction
-----------------------
In BitShares, you can propose a transactions to any account. This is
used to facilitate on-chain multisig transactions. With
python-bitshares, you can do this simply by using the ``proposer``
attribute:
.. code-block:: python
from pprint import pprint
from bitshares import BitShares
testnet = BitShares(
"wss://node.testnet.bitshares.eu",
proposer="xeroc"
)
testnet.wallet.unlock("supersecret")
pprint(testnet.transfer("init0", 1, "TEST", account="xeroc"))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment