/// <summary> /// Get the 'sender' of a transaction. /// </summary> /// <param name="tx"></param> /// <param name="coinView"></param> /// <param name="blockTxs"></param> /// <returns></returns> public static GetSenderResult GetSender(Transaction tx, CoinView coinView, IList <Transaction> blockTxs) { OutPoint prevOut = tx.Inputs[0].PrevOut; // Check the txes in this block first if (blockTxs != null && blockTxs.Count > 0) { foreach (Transaction btx in blockTxs) { if (btx.GetHash() == prevOut.Hash) { Script script = btx.Outputs[prevOut.N].ScriptPubKey; return(GetAddressFromScript(script)); } } } // Check the utxoset for the p2pk of the unspent output for this transaction if (coinView != null) { FetchCoinsResponse fetchCoinResult = coinView.FetchCoinsAsync(new uint256[] { prevOut.Hash }).Result; UnspentOutputs unspentOutputs = fetchCoinResult.UnspentOutputs.FirstOrDefault(); if (unspentOutputs == null) { throw new Exception("Unspent outputs to smart contract transaction are not present in coinview"); } Script script = unspentOutputs.Outputs[prevOut.N].ScriptPubKey; return(GetAddressFromScript(script)); } return(GetSenderResult.CreateFailure("Unable to get the sender of the transaction")); }
/// <inheritdoc /> public GetSenderResult GetSender(Transaction tx, ICoinView coinView, IList <Transaction> blockTxs) { OutPoint prevOut = tx.Inputs[0].PrevOut; // Check the txes in this block first if (blockTxs != null && blockTxs.Count > 0) { foreach (Transaction btx in blockTxs) { if (btx.GetHash() == prevOut.Hash) { if (prevOut.N >= btx.Outputs.Count) { return(GetSenderResult.CreateFailure(InvalidOutputIndex)); } Script script = btx.Outputs[prevOut.N].ScriptPubKey; return(this.GetAddressFromScript(script)); } } } // Check the utxoset for the p2pk of the unspent output for this transaction if (coinView != null) { FetchCoinsResponse fetchCoinResult = coinView.FetchCoins(new OutPoint[] { prevOut }); // The result from the coinview should never be null, so we do not check for that condition here. // It will simply not contain the requested outputs in the dictionary if they did not exist in the coindb. if (fetchCoinResult.UnspentOutputs.All(o => o.Key != prevOut)) { return(GetSenderResult.CreateFailure(OutputsNotInCoinView)); } UnspentOutput unspentOutputs = fetchCoinResult.UnspentOutputs.First(o => o.Key == prevOut).Value; // Since we now fetch a specific UTXO from the coindb instead of an entire transaction, it is no longer meaningful to check // (for the coindb at least - block transactions are handled separately above) whether the prevOut index is within bounds. // So that check has been removed from here and we proceed directly to checking spent-ness. if (unspentOutputs.Coins == null) { return(GetSenderResult.CreateFailure(OutputAlreadySpent)); } TxOut senderOutput = unspentOutputs.Coins.TxOut; return(this.GetAddressFromScript(senderOutput.ScriptPubKey)); } return(GetSenderResult.CreateFailure(UnableToGetSender)); }
/// <inheritdoc /> public GetSenderResult GetSender(Transaction tx, ICoinView coinView, IList <Transaction> blockTxs) { OutPoint prevOut = tx.Inputs[0].PrevOut; // Check the txes in this block first if (blockTxs != null && blockTxs.Count > 0) { foreach (Transaction btx in blockTxs) { if (btx.GetHash() == prevOut.Hash) { if (prevOut.N >= btx.Outputs.Count) { return(GetSenderResult.CreateFailure(InvalidOutputIndex)); } Script script = btx.Outputs[prevOut.N].ScriptPubKey; return(this.GetAddressFromScript(script)); } } } // Check the utxoset for the p2pk of the unspent output for this transaction if (coinView != null) { FetchCoinsResponse fetchCoinResult = coinView.FetchCoinsAsync(new uint256[] { prevOut.Hash }).Result; UnspentOutputs unspentOutputs = fetchCoinResult.UnspentOutputs.FirstOrDefault(); if (unspentOutputs == null) { return(GetSenderResult.CreateFailure(OutputsNotInCoinView)); } if (prevOut.N >= unspentOutputs.Outputs.Length) { return(GetSenderResult.CreateFailure(InvalidOutputIndex)); } TxOut senderOutput = unspentOutputs.Outputs[prevOut.N]; if (senderOutput == null) { return(GetSenderResult.CreateFailure(OutputAlreadySpent)); } return(this.GetAddressFromScript(senderOutput.ScriptPubKey)); } return(GetSenderResult.CreateFailure(UnableToGetSender)); }
/// <summary> /// Get the address from a P2PK or a P2PKH /// </summary> /// <param name="script"></param> /// <returns></returns> public static GetSenderResult GetAddressFromScript(Script script) { PubKey payToPubKey = PayToPubkeyTemplate.Instance.ExtractScriptPubKeyParameters(script); if (payToPubKey != null) { var address = new uint160(payToPubKey.Hash.ToBytes()); return(GetSenderResult.CreateSuccess(address)); } if (PayToPubkeyHashTemplate.Instance.CheckScriptPubKey(script)) { var address = new uint160(PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(script).ToBytes()); return(GetSenderResult.CreateSuccess(address)); } return(GetSenderResult.CreateFailure("Addresses can only be retrieved from Pay to Pub Key or Pay to Pub Key Hash")); }