Exemple #1
0
    def __init__(self,
                 prev_hash=None,
                 prev_index=None,
                 tx_output=None,
                 coin_reference=None,
                 state=CoinState.Unconfirmed):
        """
        Create an instance.

        Args:
            prev_hash (neo.Core.UInt256): (Optional if coin_reference is given) the hash of the previous transaction.
            prev_index (UInt16/int): (Optional if coin_reference is given) index of the previous transaction.
            tx_output (neo.Core.Transaction.TransactionOutput): an object representing a transaction output.
            coin_reference (neo.Core.CoinReference): (Optional if prev_hash and prev_index are given) an object representing a single UTXO / transaction input.
            state (neo.Core.State.CoinState):
        """

        self._address = None
        self._transaction = None

        if prev_hash and prev_index:
            self.Reference = CoinReference(prev_hash, prev_index)
        elif coin_reference:
            self.Reference = coin_reference
        else:
            self.Reference = None
        self.Output = tx_output
        self._state = state
Exemple #2
0
    def DeserializeExclusiveData(self, reader):
        """
        Deserialize full object.

        Args:
            reader (neo.IO.BinaryReader):

        Raises:
            Exception: If the transaction type is incorrect or if there are no claims.
        """
        self.Type = TransactionType.ClaimTransaction
        if self.Version != 0:
            raise Exception('Format Exception')

        numrefs = reader.ReadVarInt()

        claims = []
        for i in range(0, numrefs):
            c = CoinReference()
            c.Deserialize(reader)
            claims.append(c)

        self.Claims = claims
        if len(self.Claims) == 0:
            raise Exception('Format Exception')
Exemple #3
0
 def __init__(self, prev_hash=None, prev_index=None, tx_output=None, coin_reference=None, state=CoinState.Unconfirmed):
     if prev_hash and prev_index:
         self.Reference = CoinReference(prev_hash, prev_index)
     elif coin_reference:
         self.Reference = coin_reference
     else:
         self.Reference = None
     self.Output = tx_output
     self._state = state
Exemple #4
0
    def DeserializeExclusiveData(self, reader):
        """
        Deserialize full object.

        Args:
            reader (neo.IO.BinaryReader):
        """
        if self.Type == b'\x02':  # ClaimTransaction
            if self.Version != 0:
                raise FormatError('Invalid format')

            numrefs = reader.ReadVarInt()

            claims = []
            for i in range(0, numrefs):
                c = CoinReference()
                c.Deserialize(reader)
                claims.append(c)

            self.Claims = claims
            if len(self.Claims) == 0:
                raise FormatError('Invalid format')

        elif self.Type == b'\xd1':  # InvocationTransaction
            if self.Version > 1:
                raise FormatError('Invalid format')

            self.Script = reader.ReadVarBytes()

            if len(self.Script) == 0:
                raise FormatError('Invalid Format')

            if self.Version >= 1:
                self.Gas = reader.ReadFixed8()
                if self.Gas < Fixed8.Zero():
                    raise FormatError("Invalid Format")
            else:
                self.Gas = Fixed8(0)
        else:
            super(RawTransaction, self).DeserializeExclusiveData(reader=reader)
Exemple #5
0
 def DeserializeUnsignedWithoutType(self, reader):
     self.Version = reader.ReadByte()
     self.DeserializeExclusiveData(reader)
     self.Attributes = reader.ReadSerializableArray(
         'neo.Core.TX.TransactionAttribute.TransactionAttribute')
     self.inputs = [
         CoinReference(ref) for ref in reader.ReadSerializableArray(
             'neo.Core.CoinReference.CoinReference')
     ]
     self.outputs = [
         TransactionOutput(ref) for ref in reader.ReadSerializableArray(
             'neo.Core.TX.Transaction.TransactionOutput')
     ]
Exemple #6
0
    def LoadCoins(self):
        coins = {}

        try:
            for coin in Coin.select():
                reference = CoinReference(prev_hash=UInt256(coin.TxId), prev_index=coin.Index)
                output = TransactionOutput(UInt256(coin.AssetId), Fixed8(coin.Value), UInt160(coin.ScriptHash))
                walletcoin = WalletCoin.CoinFromRef(reference, output, coin.State)
                coins[reference] = walletcoin
        except Exception as e:
            logger.error("could not load coins %s " % e)

        return coins
Exemple #7
0
    def LoadCoins(self):

        coins = []

        for coin in Coin.select():
            reference = CoinReference(prev_hash=coin.TxId,
                                      prev_index=coin.Index)
            output = TransactionOutput(coin.AssetId, coin.Value,
                                       coin.ScriptHash)
            walletcoin = WalletCoin.CoinFromRef(reference, output, coin.State)
            coins.append(walletcoin)

        return coins
Exemple #8
0
class Coin(TrackableMixin):

    Output = None
    Reference = None

    _address = None
    _state = CoinState.Unconfirmed

    @staticmethod
    def CoinFromRef(coin_ref, tx_output, state=CoinState.Unconfirmed):
        coin = Coin(coin_reference=coin_ref, tx_output=tx_output, state=state)
        return coin

    def __init__(self,
                 prev_hash=None,
                 prev_index=None,
                 tx_output=None,
                 coin_reference=None,
                 state=CoinState.Unconfirmed):
        if prev_hash and prev_index:
            self.Reference = CoinReference(prev_hash, prev_index)
        elif coin_reference:
            self.Reference = coin_reference
        else:
            self.Reference = None
        self.Output = tx_output
        self._state = state

    @property
    def Address(self):
        if self._address is None:
            self._address = Crypto.ToAddress(self.TXOutput.ScriptHash)
        return self._address

    @property
    def State(self):
        return self._state

    @State.setter
    def State(self, value):
        self._state = value

    def Equals(self, other):
        if other is None or other is not self: return False
        return True

    def ToJson(self):
        return {
            'Reference': self.Reference.ToJson(),
            'Output': self.Output.ToJson()
        }
Exemple #9
0
    def AddInputs(self, asset):
        """
        Specify inputs for the transaction based on the asset to be sent.
        NOTE: Can be used multiple times if sending multiple assets (i.e. NEO and GAS).

        Args:
            asset: (str) the asset name or asset hash
        """
        if not isinstance(asset, str):
            raise TypeError('Please enter the asset as a string.')

        if not self.BALANCE:
            raise RawTXError(
                'Please specify a source address before adding inputs.')

        if asset[0:1] == "0x":
            asset == asset[2:]
        if asset.lower() == "neo":
            assetId = self.neo_asset_id
        elif asset == self.neo_asset_id:
            assetId = self.neo_asset_id
        elif asset.lower() == "gas":
            assetId = self.gas_asset_id
        elif asset == self.gas_asset_id:
            assetId = self.gas_asset_id
        else:
            raise AssetError(
                f'Asset {asset} not found. If trying to send tokens use the `buildTokenTransfer` function.'
            )

        for asset in self.BALANCE:
            if assetId == asset['asset_hash']:
                if not asset['unspent']:
                    raise AssetError('No unspent assets found.')
                for unspent in asset['unspent']:
                    self.inputs.append(
                        CoinReference(prev_hash=UInt256.ParseString(
                            unspent['txid']),
                                      prev_index=unspent['n']))
        if not self.inputs:
            raise AssetError(
                'No matching assets found at the specified source address.')
Exemple #10
0
    def AddClaim(self, claim_addr, to_addr=None):
        """
        Builds a claim transaction for the specified address.

        Args:
            claim_addr: (str) the address from which the claim is being constructed (e.g. 'AJQ6FoaSXDFzA6wLnyZ1nFN7SGSN2oNTc3'). NOTE: Claimed GAS is sent to the claim_addr by default
            to_addr: (str, optional) specify a different destination NEO address (e.g. 'AJQ6FoaSXDFzA6wLnyZ1nFN7SGSN2oNTc3')
        """
        dest_scripthash = Helper.AddrStrToScriptHash(
            claim_addr)  # also verifies if the address is valid
        self.SOURCE_SCRIPTHASH = dest_scripthash

        url = self._network + self._get_claimable + claim_addr
        res = requests.get(url=url)

        if not res.status_code == 200:
            raise NetworkError(
                'Neoscan request failed. Please check your internet connection.'
            )

        res = res.json()
        available = res["unclaimed"]
        if available == 0:
            raise AssetError(
                f"Address {claim_addr} has 0 unclaimed GAS. Please ensure the correct network is selected or specify a difference source address."
            )

        for ref in res['claimable']:
            self.Claims.append(
                CoinReference(prev_hash=UInt256.ParseString(ref['txid']),
                              prev_index=ref['n']))

        if to_addr:
            dest_scripthash = Helper.AddrStrToScriptHash(
                to_addr)  # also verifies if the address is valid

        self.outputs.append(
            TransactionOutput(AssetId=UInt256.ParseString(self.gas_asset_id),
                              Value=Fixed8.FromDecimal(available),
                              script_hash=dest_scripthash))
Exemple #11
0
    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.
        """
        added = set()
        changed = set()
        deleted = set()

        try:
            # go through the list of transactions in the block and enumerate
            # over their outputs
            for tx in block.FullTransactions:

                for index, output in enumerate(tx.outputs):

                    # check to see if the outputs in the tx are in this wallet
                    state = self.CheckAddressState(output.ScriptHash)

                    if state & AddressState.InWallet > 0:

                        # if its in the wallet, check to see if the coin exists yet
                        key = CoinReference(tx.Hash, index)

                        # if it exists, update it, otherwise create a new one
                        if key in self._coins.keys():
                            coin = self._coins[key]
                            coin.State |= CoinState.Confirmed
                            changed.add(coin)
                        else:
                            newcoin = Coin.CoinFromRef(coin_ref=key, tx_output=output, state=CoinState.Confirmed, transaction=tx)
                            self._coins[key] = newcoin
                            added.add(newcoin)

                        if state & AddressState.WatchOnly > 0:
                            self._coins[key].State |= CoinState.WatchOnly
                            changed.add(self._coins[key])

            # now iterate over the inputs of the tx and do the same
            for tx in block.FullTransactions:

                for input in tx.inputs:

                    if input in self._coins.keys():
                        if self._coins[input].Output.AssetId == Blockchain.SystemShare().Hash:
                            coin = self._coins[input]
                            coin.State |= CoinState.Spent | CoinState.Confirmed
                            changed.add(coin)

                        else:
                            deleted.add(self._coins[input])
                            del self._coins[input]

            for claimTx in [tx for tx in block.Transactions if tx.Type == TransactionType.ClaimTransaction]:

                for ref in claimTx.Claims:
                    if ref in self._coins.keys():
                        deleted.add(self._coins[ref])
                        del self._coins[ref]

            # update the current height of the wallet
            self._current_height += 1

            # in the case that another wallet implementation needs to do something
            # with the coins that have been changed ( ie persist to db ) this
            # method is called
            self.OnProcessNewBlock(block, added, changed, deleted)

            # this is not necessary at the moment, but any outside process
            # that wants to subscribe to the balance changed event could do
            # so from the BalanceChanged method
            if len(added) + len(deleted) + len(changed) > 0:
                self.BalanceChanged()

        except Exception as e:
            traceback.print_stack()
            traceback.print_exc()
            logger.error("could not process %s " % e)
Exemple #12
0
    def SaveTransaction(self, tx):
        """
        This method is used to after a transaction has been made by this wallet.  It updates the states of the coins
        In the wallet to reflect the new balance, but the coins remain in a ``CoinState.UNCONFIRMED`` state until
        The transaction has been processed by the network.

        The results of these updates can be used by overriding the ``OnSaveTransaction`` method, and, for example
        persisting the results to a database.

        Args:
            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.
        """
        coins = self.GetCoins()
        changed = []
        added = []
        deleted = []
        found_coin = False
        for input in tx.inputs:
            coin = None

            for coinref in coins:
                test_coin = coinref.Reference
                if test_coin == input:
                    coin = coinref

            if coin is None:
                return False
            if coin.State & CoinState.Spent > 0:
                return False
            elif coin.State & CoinState.Confirmed == 0:
                return False

            coin.State |= CoinState.Spent
            coin.State &= ~CoinState.Confirmed
            changed.append(coin)

        for index, output in enumerate(tx.outputs):

            state = self.CheckAddressState(output.ScriptHash)

            key = CoinReference(tx.Hash, index)

            if state & AddressState.InWallet > 0:
                newcoin = Coin.CoinFromRef(coin_ref=key, tx_output=output, state=CoinState.Unconfirmed)
                self._coins[key] = newcoin

                if state & AddressState.WatchOnly > 0:
                    newcoin.State |= CoinState.WatchOnly

                added.append(newcoin)

        if isinstance(tx, ClaimTransaction):
            # do claim stuff
            for claim in tx.Claims:
                claim_coin = self._coins[claim]
                claim_coin.State |= CoinState.Claimed
                claim_coin.State &= ~CoinState.Confirmed
                changed.append(claim_coin)

        self.OnSaveTransaction(tx, added, changed, deleted)

        return True
Exemple #13
0
def example1():
    neo_asset_id = Blockchain.GetSystemShare().Hash
    gas_asset_id = Blockchain.GetSystemCoin().Hash

    source_address = "AJQ6FoaSXDFzA6wLnyZ1nFN7SGSN2oNTc3"
    source_script_hash = address_to_scripthash(source_address)

    destination_address = "Ad9A1xPbuA5YBFr1XPznDwBwQzdckAjCev"
    destination_script_hash = address_to_scripthash(destination_address)

    # Let's start with building a ContractTransaction
    # The constructor already sets the correct `Type` and `Version` fields, so we do not have to worry about that
    contract_tx = ContractTransaction()

    # the ContractTransaction type has no special data, so we do not have to do anything there

    # Next we can add Attributes if we want. Again the various types are described in point 4. of the main link above
    # We will add a simple "description"
    contract_tx.Attributes.append(
        TransactionAttribute(usage=TransactionAttributeUsage.Description,
                             data="My raw contract transaction description"))

    # The next field we will set are the inputs. The inputs neo-python expects are of the type ``CoinReference``
    # To create these inputs we will need the usual `PrevHash` and `PrevIndex` values.
    # You can get the required data by using e.g. the neoscan.io API: https://api.neoscan.io/docs/index.html#api-v1-get-3
    # The `PrevHash` field equals to neoscan's `balance.unspent[index].txid` key, and `PrevIndex` comes from `balance.unspent[index].n`
    # It is up to the transaction creator to make sure that the sum of all input ``value`` fields is equal to or bigger than the amount that's intended to be send
    # The below values are taken from data out of the `neo-test1-w.wallet` fixture wallet (a wallet neo-python uses for internal testing)
    input1 = CoinReference(prev_hash=UInt256(data=binascii.unhexlify(
        '949354ea0a8b57dfee1e257a1aedd1e0eea2e5837de145e8da9c0f101bfccc8e')),
                           prev_index=1)
    contract_tx.inputs = [input1]

    # Next we will create the outputs.
    # The above input has a value of 50. We will create 2 outputs.

    # 1 output for sending 3 NEO to a specific destination address
    send_to_destination_output = TransactionOutput(
        AssetId=neo_asset_id,
        Value=Fixed8.FromDecimal(3),
        script_hash=destination_script_hash)

    # and a second output for sending the change back to ourselves
    return_change_output = TransactionOutput(AssetId=neo_asset_id,
                                             Value=Fixed8.FromDecimal(47),
                                             script_hash=source_script_hash)

    contract_tx.outputs = [send_to_destination_output, return_change_output]

    # at this point we've build our unsigned transaction and it's time to sign it before we get the raw output that we can send to the network via RPC
    # we need to create a Wallet instance for helping us with signing
    wallet = UserWallet.Create('path',
                               to_aes_key('mypassword'),
                               generate_default_key=False)

    # if you have a WIF use the following
    # this WIF comes from the `neo-test1-w.wallet` fixture wallet
    private_key = KeyPair.PrivateKeyFromWIF(
        "Ky94Rq8rb1z8UzTthYmy1ApbZa9xsKTvQCiuGUZJZbaDJZdkvLRV")

    # if you have a NEP2 encrypted key use the following instead
    # private_key = KeyPair.PrivateKeyFromNEP2("NEP2 key string", "password string")

    # we add the key to our wallet
    wallet.CreateKey(private_key)

    # and now we're ready to sign
    context = ContractParametersContext(contract_tx)
    wallet.Sign(context)

    contract_tx.scripts = context.GetScripts()

    print(contract_tx.Hash.ToString())

    raw_tx = contract_tx.ToArray()
Exemple #14
0
    def ProcessNewBlock(self, block):

        added = set()
        changed = set()
        deleted = set()

        self._lock.acquire()
        try:

            for tx in block.Transactions:

                for index, output in enumerate(tx.outputs):

                    state = self.CheckAddressState(output.ScriptHash)

                    if state > 0:
                        key = CoinReference(tx.Hash, index)

                        found = False
                        for coin in self._coins:
                            if coin.CoinRef.Equals(key):
                                coin.State |= CoinState.Confirmed
                                changed.add(coin.CoinRef)
                                found = True
                        if not found:
                            newcoin = Coin.CoinFromRef(
                                key, output, state=CoinState.Confirmed)
                            self._coins.append(newcoin)
                            added.add(newcoin.CoinRef)

                        if state == AddressState.WatchOnly:
                            for coin in self._coins:
                                if coin.CoinRef.Equals(key):
                                    coin.State |= CoinState.WatchOnly
                                    changed.add(coin.CoinRef)

            for tx in block.Transactions:

                for input in tx.inputs:

                    for coin in self._coins:
                        if coin.CoinRef.Equals(input):

                            if coin.TXOutput.AssetId == Blockchain.SystemShare(
                            ).Hash():
                                coin.State |= CoinState.Spent | CoinState.Confirmed
                                changed.add(coin.CoinRef)
                            else:
                                self._coins.remove(coin)
                                deleted.add(coin.CoinRef)

            for claimTx in [
                    tx for tx in block.Transactions
                    if tx.Type == TransactionType.ClaimTransaction
            ]:
                for ref in claimTx.Claims:
                    if ref in self._coins:
                        self._coins.remove(ref)
                        deleted.add(ref)

            self._current_height += 1
            self.OnProcessNewBlock(block, added, changed, deleted)

            if len(added) + len(deleted) + len(changed) > 0:
                self.BalanceChanged()

        except Exception as e:
            print("could not process: %s " % e)
        finally:
            self._lock.release()
Exemple #15
0
 def __init__(self, prev_hash=None, prev_index=None, tx_output=None, state=CoinState.Unconfirmed):
     self.CoinRef = CoinReference(prev_hash, prev_index)
     self.TXOutput = tx_output
     self._state = state
Exemple #16
0
    def ProcessNewBlock(self, block):

        added = set()
        changed = set()
        deleted = set()

        try:

            for tx in block.FullTransactions:

                for index, output in enumerate(tx.outputs):

                    state = self.CheckAddressState(output.ScriptHash)

                    if state & AddressState.InWallet > 0:

                        key = CoinReference(tx.Hash, index)

                        if key in self._coins.keys():
                            coin = self._coins[key]
                            coin.State |= CoinState.Confirmed
                            changed.add(coin)

                        else:
                            newcoin = Coin.CoinFromRef(
                                coin_ref=key,
                                tx_output=output,
                                state=CoinState.Confirmed)
                            self._coins[key] = newcoin
                            added.add(newcoin)

                        if state & AddressState.WatchOnly > 0:

                            self._coins[key].State |= CoinState.WatchOnly
                            changed.add(self._coins[key])

            for tx in block.FullTransactions:

                for input in tx.inputs:

                    if input in self._coins.keys():

                        if self._coins[input].Output.AssetId.ToBytes(
                        ) == Blockchain.SystemShare().Hash.ToBytes():
                            self._coins[
                                input].State |= CoinState.Spent | CoinState.Confirmed
                            changed.add(self._coins[input])

                        else:
                            deleted.add(self._coins[input])
                            del self._coins[input]

            for claimTx in [
                    tx for tx in block.Transactions
                    if tx.Type == TransactionType.ClaimTransaction
            ]:

                for ref in claimTx.Claims:
                    if ref in self._coins.keys():
                        deleted.add(self._coins[ref])
                        del self._coins[ref]

            self._current_height += 1
            self.OnProcessNewBlock(block, added, changed, deleted)

            if len(added) + len(deleted) + len(changed) > 0:
                self.BalanceChanged()

        except Exception as e:
            traceback.print_stack()
            traceback.print_exc()
            print("could not process %s " % e)
Exemple #17
0
class Coin(TrackableMixin):
    @staticmethod
    def CoinFromRef(coin_ref,
                    tx_output,
                    state=CoinState.Unconfirmed,
                    transaction=None):
        """
        Get a Coin object using a CoinReference.

        Args:
            coin_ref (neo.Core.CoinReference): an object representing a single UTXO / transaction input.
            tx_output (neo.Core.Transaction.TransactionOutput): an object representing a transaction output.
            state (neo.Core.State.CoinState):

        Returns:
            Coin: self.
        """
        coin = Coin(coin_reference=coin_ref, tx_output=tx_output, state=state)
        coin._transaction = transaction
        return coin

    def __init__(self,
                 prev_hash=None,
                 prev_index=None,
                 tx_output=None,
                 coin_reference=None,
                 state=CoinState.Unconfirmed):
        """
        Create an instance.

        Args:
            prev_hash (neo.Core.UInt256): (Optional if coin_reference is given) the hash of the previous transaction.
            prev_index (UInt16/int): (Optional if coin_reference is given) index of the previous transaction.
            tx_output (neo.Core.Transaction.TransactionOutput): an object representing a transaction output.
            coin_reference (neo.Core.CoinReference): (Optional if prev_hash and prev_index are given) an object representing a single UTXO / transaction input.
            state (neo.Core.State.CoinState):
        """

        self._address = None
        self._transaction = None

        if prev_hash and prev_index:
            self.Reference = CoinReference(prev_hash, prev_index)
        elif coin_reference:
            self.Reference = coin_reference
        else:
            self.Reference = None
        self.Output = tx_output
        self._state = state

    @property
    def Transaction(self):
        return self._transaction

    @property
    def Address(self):
        """
        Get the wallet address associated with the coin.

        Returns:
            str: base58 encoded string representing the wallet address.
        """
        if self._address is None:
            self._address = Crypto.ToAddress(self.Output.ScriptHash)
        return self._address

    @property
    def State(self):
        """
        Get the coin state.

        Returns:
            neo.Core.State.CoinState: the coins state.
        """
        return self._state

    @State.setter
    def State(self, value):
        """
        Set the coin state.

        Args:
            value (neo.Core.State.CoinState): the new coin state.
        """
        self._state = value

    def Equals(self, other):
        """
        Compare `other` to self.

        Args:
            other (object):

        Returns:
            True if object is equal to self. False otherwise.
        """
        if other is None or other is not self or type(other) is not Coin:
            return False
        return True

    def __hash__(self):
        return int.from_bytes(
            self.Reference.PrevHash.Data + bytearray(self.Reference.PrevIndex),
            'little')

    def __eq__(self, other):
        return self.Equals(other)

    def RefToBytes(self):
        vin_index = bytearray(self.Reference.PrevIndex.to_bytes(1, 'little'))
        vin_tx = self.Reference.PrevHash.Data
        vindata = vin_tx + vin_index
        return vindata

    def ToJson(self):
        """
        Convert object members to a dictionary that can be parsed as JSON.

        Returns:
             dict:
        """
        return {
            'Reference': self.Reference.ToJson(),
            'Output': self.Output.ToJson(index=0),
        }