Skip to content
This repository has been archived by the owner on Nov 15, 2021. It is now read-only.

Commit

Permalink
Merge branch 'development' of github.com:CityOfZion/neo-python into d…
Browse files Browse the repository at this point in the history
…evelopment
  • Loading branch information
localhuman committed Nov 24, 2017
2 parents 88de403 + 49ed922 commit e521474
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 71 deletions.
58 changes: 42 additions & 16 deletions neo/Implementations/Wallets/peewee/UserWallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,19 +75,43 @@ def Open(path, password):

@staticmethod
def Create(path, password):
"""
Create a new user wallet.
Args:
path (str): A path indicating where to create or open the wallet i.e. "/Wallets/mywallet".
password (str): a 10 characters minimum password to secure the wallet with.
Returns:
UserWallet: a UserWallet instance.
"""
wallet = UserWallet(path=path, passwordKey=password, create=True)
wallet.CreateKey()
return wallet

def CreateKey(self, prikey=None):
"""
Create a KeyPair and store it encrypted in the database.
Args:
private_key (iterable_of_ints): (optional) 32 byte private key.
Returns:
KeyPair: a KeyPair instance.
"""
account = super(UserWallet, self).CreateKey(private_key=prikey)
self._keys[account.PublicKeyHash.ToBytes()] = account
self.OnCreateAccount(account)
contract = WalletContract.CreateSignatureContract(account.PublicKey)
self.AddContract(contract)
return account

def OnCreateAccount(self, account):
"""
Save a KeyPair in encrypted form into the database.
Args:
account (KeyPair):
"""
pubkey = account.PublicKey.encode_point(False)
pubkeyunhex = binascii.unhexlify(pubkey)
pub = pubkeyunhex[1:65]
Expand All @@ -98,11 +122,16 @@ def OnCreateAccount(self, account):

db_account, created = Account.get_or_create(
PrivateKeyEncrypted=encrypted_pk, PublicKeyHash=account.PublicKeyHash.ToBytes())
db_account.PrivateKeyEncrypted = encrypted_pk
db_account.save()
self.__dbaccount = db_account

def AddContract(self, contract):
"""
Add a contract to the database.
Args:
contract(neo.SmartContract.Contract): a Contract instance.
"""
super(UserWallet, self).AddContract(contract)

db_contract = None
Expand All @@ -113,22 +142,19 @@ def AddContract(self, contract):
except Exception as e:
logger.error("contract does not exist yet")

if db_contract is not None:
db_contract.PublicKeyHash = contract.PublicKeyHash.ToBytes()
else:
sh = bytes(contract.ScriptHash.ToArray())
address, created = Address.get_or_create(ScriptHash=sh)
address.IsWatchOnly = False
address.save()
db_contract = Contract.create(RawData=contract.ToArray(),
ScriptHash=contract.ScriptHash.ToBytes(),
PublicKeyHash=contract.PublicKeyHash.ToBytes(),
Address=address,
Account=self.__dbaccount)
sh = bytes(contract.ScriptHash.ToArray())
address, created = Address.get_or_create(ScriptHash=sh)
address.IsWatchOnly = False
address.save()
db_contract = Contract.create(RawData=contract.ToArray(),
ScriptHash=contract.ScriptHash.ToBytes(),
PublicKeyHash=contract.PublicKeyHash.ToBytes(),
Address=address,
Account=self.__dbaccount)

logger.debug("Creating db contract %s " % db_contract)
logger.debug("Creating db contract %s " % db_contract)

db_contract.save()
db_contract.save()

def AddWatchOnly(self, script_hash):
super(UserWallet, self).AddWatchOnly(script_hash)
Expand Down
8 changes: 8 additions & 0 deletions neo/SmartContract/Contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,15 @@ def CreateMultiSigContract(publicKeyHash, m, publicKeys):

@staticmethod
def CreateSignatureContract(publicKey):
"""
Create a signature contract.
Args:
publicKey (edcsa.Curve.point): i.e. KeyPair.PublicKey.
Returns:
neo.SmartContract.Contract: a Contract instance.
"""
script = Contract.CreateSignatureRedeemScript(publicKey)
params = bytearray([ContractParameterType.Signature])
encoded = publicKey.encode_point(True)
Expand Down
107 changes: 58 additions & 49 deletions neo/Wallets/Wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ def __init__(self, path, passwordKey, create):
"""
Args:
path: (str) A path indicating where to create or open the wallet
passwordKey: (str) A password to use in creating or opening the wallet
create: (bool) Whether to create the wallet or simply open
path (str): A path indicating where to create or open the wallet.
passwordKey (str): A password to use in creating or opening the wallet.
create (bool): Whether to create the wallet or simply open.
"""

self.AddressVersion = settings.ADDRESS_VERSION
Expand Down Expand Up @@ -137,7 +137,7 @@ def BuildDatabase(self):

def AddContract(self, contract):
"""
Add a contract to the wallet
Add a contract to the wallet.
Args:
contract (Contract): a contract of type neo.SmartContract.Contract.
Expand Down Expand Up @@ -341,14 +341,14 @@ def DeleteAddress(self, script_hash):

def FindCoinsByVins(self, vins):
"""
Looks through the current collection of coins in a wallet
and chooses coins that match the specified CoinReference objects
and chooses coins that match the specified CoinReference objects.
Args:
vins: A list of ``neo.Core.CoinReference`` objects
vins: A list of ``neo.Core.CoinReference`` objects.
Returns:
list: A list of ``neo.Wallet.Coin`` objects
list: A list of ``neo.Wallet.Coin`` objects.
"""
ret = []
for coin in self.GetCoins():
Expand All @@ -362,14 +362,15 @@ def FindCoinsByVins(self, vins):

def FindUnspentCoins(self, from_addr=None, use_standard=False, watch_only_val=0):
"""
Finds unspent coin objects in the wallet
Finds unspent coin objects in the wallet.
Args:
from_addr: (UInt160): a bytearray (len 20) representing an address
use_standard: (bool): whether or not to only include standard contracts ( i.e not a smart contract addr )
watch_only_val: (int): a flag ( 0 or 64 ) indicating whether or not to find coins that are in 'watch only' addresses
from_addr (UInt160): a bytearray (len 20) representing an address.
use_standard (bool): whether or not to only include standard contracts ( i.e not a smart contract addr ).
watch_only_val (int): a flag ( 0 or 64 ) indicating whether or not to find coins that are in 'watch only' addresses.
Returns:
list: a list of ``neo.Wallet.Coins`` in the wallet that are not spent
list: a list of ``neo.Wallet.Coins`` in the wallet that are not spent.
"""
ret = []
for coin in self.GetCoins():
Expand Down Expand Up @@ -405,12 +406,13 @@ def FindUnspentCoins(self, from_addr=None, use_standard=False, watch_only_val=0)

def FindUnspentCoinsByAsset(self, asset_id, from_addr=None, use_standard=False, watch_only_val=0):
"""
Finds unspent coin objects in the wallet limited to those of a certain asset type
Finds unspent coin objects in the wallet limited to those of a certain asset type.
Args:
asset_id: (UInt256): a bytearray (len 32) representing an asset on the blockchain
from_addr: (UInt160): a bytearray (len 20) representing an address
use_standard: (bool): whether or not to only include standard contracts ( i.e not a smart contract addr )
watch_only_val: (int): a flag ( 0 or 64 ) indicating whether or not to find coins that are in 'watch only' addresses
asset_id (UInt256): a bytearray (len 32) representing an asset on the blockchain.
from_addr (UInt160): a bytearray (len 20) representing an address.
use_standard (bool): whether or not to only include standard contracts ( i.e not a smart contract addr ).
watch_only_val (int): a flag ( 0 or 64 ) indicating whether or not to find coins that are in 'watch only' addresses.
Returns:
list: a list of ``neo.Wallet.Coin`` in the wallet that are not spent
Expand All @@ -421,16 +423,17 @@ def FindUnspentCoinsByAsset(self, asset_id, from_addr=None, use_standard=False,

def FindUnspentCoinsByAssetAndTotal(self, asset_id, amount, from_addr=None, use_standard=False, watch_only_val=0):
"""
Finds unspent coin objects totalling a requested value in the wallet limited to those of a certain asset type
Finds unspent coin objects totalling a requested value in the wallet limited to those of a certain asset type.
Args:
asset_id: (UInt256): a bytearray (len 32) representing an asset on the blockchain
amount: (int): the amount of unspent coins that are being requested
from_addr: (UInt160): a bytearray (len 20) representing an address
use_standard: (bool): whether or not to only include standard contracts ( i.e not a smart contract addr )
watch_only_val: (int): a flag ( 0 or 64 ) indicating whether or not to find coins that are in 'watch only' addresses
asset_id (UInt256): a bytearray (len 32) representing an asset on the blockchain.
amount (int): the amount of unspent coins that are being requested.
from_addr (UInt160): a bytearray (len 20) representing an address.
use_standard (bool): whether or not to only include standard contracts ( i.e not a smart contract addr ).
watch_only_val (int): a flag ( 0 or 64 ) indicating whether or not to find coins that are in 'watch only' addresses.
Returns:
list: a list of ``neo.Wallet.Coin`` in the wallet that are not spent. this list is empty if there are not enough coins to satisfy the request
list: a list of ``neo.Wallet.Coin`` in the wallet that are not spent. this list is empty if there are not enough coins to satisfy the request.
"""
coins = self.FindUnspentCoinsByAsset(asset_id, from_addr=from_addr,
use_standard=use_standard, watch_only_val=watch_only_val)
Expand All @@ -454,7 +457,8 @@ def FindUnspentCoinsByAssetAndTotal(self, asset_id, amount, from_addr=None, use_

def GetUnclaimedCoins(self):
"""
Gets coins in the wallet that have not been 'claimed', or redeemed for their gas value on the blockchain
Gets coins in the wallet that have not been 'claimed', or redeemed for their gas value on the blockchain.
Returns:
list: a list of ``neo.Wallet.Coin`` that have 'claimable' value
"""
Expand All @@ -476,9 +480,10 @@ def GetUnclaimedCoins(self):

def GetAvailableClaimTotal(self):
"""
Gets the total amount of Gas that this wallet is able to claim at a given moment
Gets the total amount of Gas that this wallet is able to claim at a given moment.
Returns:
Fixed8: the amount of Gas available to claim as a Fixed8 number
Fixed8: the amount of Gas available to claim as a Fixed8 number.
"""
coinrefs = [coin.Reference for coin in self.GetUnclaimedCoins()]
bonus = Blockchain.CalculateBonusIgnoreClaimed(coinrefs, True)
Expand All @@ -487,9 +492,10 @@ def GetAvailableClaimTotal(self):
def GetUnavailableBonus(self):
"""
Gets the total claimable amount of Gas in the wallet that is not available to claim
because it has not yet been spent
because it has not yet been spent.
Returns:
Fixed8: the amount of Gas unavailable to claim
Fixed8: the amount of Gas unavailable to claim.
"""
height = Blockchain.Default().Height + 1
unspents = self.FindUnspentCoinsByAsset(Blockchain.SystemShare().Hash)
Expand Down Expand Up @@ -618,14 +624,13 @@ def LoadNEP5Tokens(self):
def ProcessBlocks(self):
"""
Method called on a loop to check the current height of the blockchain. If the height of the blockchain
is less than the current stored height in the wallet, we get the next block in line and
is more than the current stored height in the wallet, we get the next block in line and
processes it.
In the case that the wallet height is far behind the height of the blockchain, we do this 500
blocks at a time.
"""
blockcount = 0

while self._current_height <= Blockchain.Default().Height and blockcount < 500:

block = Blockchain.Default().GetBlockByHeight(self._current_height)
Expand All @@ -641,8 +646,9 @@ def ProcessNewBlock(self, block):
"""
Processes a block on the blockchain. This should be done in a sequential order, ie block 4 should be
only processed after block 3.
Args:
block: (neo.Core.Block) a block on the blockchain
block: (neo.Core.Block) a block on the blockchain.
"""
added = set()
changed = set()
Expand Down Expand Up @@ -723,7 +729,7 @@ def ProcessNewBlock(self, block):
def Rebuild(self):
"""
Sets the current height to 0 and now `ProcessBlocks` will start from
the beginning of the blockchain
the beginning of the blockchain.
"""
self._coins = {}
self._current_height = 0
Expand Down Expand Up @@ -888,16 +894,19 @@ def GetDefaultContract(self):
Get the default contract.
Returns:
contract (Contract): if Successful, a contract of type neo.SmartContract.Contract, otherwise None
contract (Contract): if Successful, a contract of type neo.SmartContract.Contract, otherwise an Exception.
Raises:
Exception: if no default contract is found.
Note:
Prints a warning to the console if the default contract could not be found.
"""
try:
return self.GetContracts()[0]
except Exception as e:
logger.error("Could not find default contract")
return None
logger.error("Could not find default contract: %s" % str(e))
raise

def GetKeys(self):
"""
Expand Down Expand Up @@ -963,20 +972,20 @@ def MakeTransaction(self,
use_vins_for_asset=None):
"""
This method is used to to calculate the necessary TransactionInputs (CoinReferences) and TransactionOutputs to
be used when creating a transaction that involves an exchange of system assets, ( NEO, Gas, etc )
be used when creating a transaction that involves an exchange of system assets, ( NEO, Gas, etc ).
Args:
tx: (Transaction) The Transaction to be used
change_address: (UInt160) The address any change for the transaction should be returned to
fee: (Fixed8) A fee to be attached to the Transaction for network processing purposes
from_addr: (UInt160) If present, all CoinReferences selected will only come from this address
use_standard: (bool) If true, only CoinReferences from standard addresses ( not contracts that are smart contracts ) will be used
watch_only_val: (int) 0 or CoinState.WATCH_ONLY, if present only choose coins that are in a WatchOnly address
exclude_vin: (list) A list of CoinReferences to NOT use in the making of this tx
use_vins_for_asset: (list) A list of CoinReferences to use
tx (Transaction): The Transaction to be used.
change_address (UInt160): The address any change for the transaction should be returned to.
fee (Fixed8): A fee to be attached to the Transaction for network processing purposes.
from_addr (UInt160): If present, all CoinReferences selected will only come from this address.
use_standard (bool): If true, only CoinReferences from standard addresses ( not contracts that are smart contracts ) will be used.
watch_only_val (int): 0 or CoinState.WATCH_ONLY, if present only choose coins that are in a WatchOnly address.
exclude_vin (list): A list of CoinReferences to NOT use in the making of this tx.
use_vins_for_asset (list): A list of CoinReferences to use.
Returns:
tx: (Transaction) Returns the transaction with oupdated inputs and outputs
tx: (Transaction) Returns the transaction with oupdated inputs and outputs.
"""

tx.ResetReferences()
Expand Down Expand Up @@ -1068,7 +1077,7 @@ def SaveTransaction(self, tx):
persisting the results to a database.
Args:
tx (Transaction): The transaction that has been made by this wallet
tx (Transaction): The transaction that has been made by this wallet.
Returns:
bool: True is successfully processes, otherwise False if input is not in the coin list, already spent or not confirmed.
Expand Down Expand Up @@ -1129,7 +1138,7 @@ def Sign(self, context):
Sign the verifiable items ( Transaction, Block, etc ) in the context with the Keypairs in this wallet.
Args:
context (ContractParameterContext): the context to sign
context (ContractParameterContext): the context to sign.
Returns:
bool: if signing is successful for all contracts in this wallet.
Expand Down
16 changes: 10 additions & 6 deletions prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,16 +218,20 @@ def do_create(self, arguments):

try:
self.Wallet = UserWallet.Create(path=path, password=passwd1)
contract = self.Wallet.GetDefaultContract()
key = self.Wallet.GetKey(contract.PublicKeyHash)
print("Wallet %s " % json.dumps(self.Wallet.ToJson(), indent=4))
print("pubkey %s " % key.PublicKey.encode_point(True))
except Exception as e:
print("Exception creating wallet: %s " % e)
self.Wallet = None
if os.path.isfile(path):
try:
os.remove(path)
except Exception as e:
print("Could not remove {}: {}".format(path, e))
return

contract = self.Wallet.GetDefaultContract()
key = self.Wallet.GetKey(contract.PublicKeyHash)

print("Wallet %s " % json.dumps(self.Wallet.ToJson(), indent=4))
print("pubkey %s " % key.PublicKey.encode_point(True))

self._walletdb_loop = task.LoopingCall(self.Wallet.ProcessBlocks)
self._walletdb_loop.start(1)

Expand Down

0 comments on commit e521474

Please sign in to comment.