Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions src/Blockcore/Consensus/ScriptAddressReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,36 @@ namespace Blockcore.Consensus
public class ScriptAddressReader : IScriptAddressReader
{
/// <inheritdoc cref="IScriptAddressReader.GetAddressFromScriptPubKey"/>
public string GetAddressFromScriptPubKey(Network network, Script script)
public ScriptAddressResult GetAddressFromScriptPubKey(Network network, Script script)
{
ScriptTemplate scriptTemplate = network.StandardScriptsRegistry.GetTemplateFromScriptPubKey(script);

string destinationAddress = null;
var destinationAddress = new ScriptAddressResult();

switch (scriptTemplate?.Type)
{
// Pay to PubKey can be found in outputs of staking transactions.
case TxOutType.TX_PUBKEY:
PubKey pubKey = PayToPubkeyTemplate.Instance.ExtractScriptPubKeyParameters(script);
destinationAddress = pubKey.GetAddress(network).ToString();
destinationAddress.Address = pubKey.GetAddress(network).ToString();
break;
// Pay to PubKey hash is the regular, most common type of output.
case TxOutType.TX_PUBKEYHASH:
destinationAddress = script.GetDestinationAddress(network).ToString();
destinationAddress.Address = script.GetDestinationAddress(network).ToString();
break;

case TxOutType.TX_SCRIPTHASH:
destinationAddress = script.GetDestinationAddress(network).ToString();
destinationAddress.Address = script.GetDestinationAddress(network).ToString();
break;

case TxOutType.TX_COLDSTAKE:
destinationAddress = this.GetColdStakeAddresses(network, script);
break;

case TxOutType.TX_SEGWIT:
destinationAddress = script.GetDestinationAddress(network).ToString();
destinationAddress.Address = script.GetDestinationAddress(network).ToString();
break;

case TxOutType.TX_NONSTANDARD:
case TxOutType.TX_MULTISIG:
case TxOutType.TX_NULL_DATA:
Expand All @@ -40,5 +47,15 @@ public string GetAddressFromScriptPubKey(Network network, Script script)

return destinationAddress;
}

public ScriptAddressResult GetColdStakeAddresses(Network network, Script script)
{
var destinationAddressResult = script.GetColdStakeDestinationAddress(network);
return new ScriptAddressResult()
{
HotAddress = destinationAddressResult.hotAddress.ToString(),
ColdAddress = destinationAddressResult.coldAddress.ToString()
};
}
}
}
}
42 changes: 42 additions & 0 deletions src/Blockcore/Consensus/ScriptAddressResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
namespace Blockcore.Consensus
{
/// <summary>
/// The script result address.
/// </summary>
public class ScriptAddressResult
{
/// <summary>
/// Will return the script public address if exists, Otherwise returns <see cref="string.Empty"/>
/// </summary>
public static implicit operator string(ScriptAddressResult scriptAddressResult)
{
return scriptAddressResult.Address.ToString();
}

/// <summary>
/// If Address, Hot and Cold addresses are all empty, it will return true, otherwise false.
/// </summary>
public bool IsNullOrEmpty()
{
return string.IsNullOrEmpty(this.Address) &&
string.IsNullOrEmpty(this.HotAddress) &&
string.IsNullOrEmpty(this.ColdAddress);
}

/// <summary>
/// Will return the script public address if exists, Otherwise returns <see cref="string.Empty"/>
/// </summary>
public string Address { get; set; } = string.Empty;

/// <summary>
/// Will return the script hot public address if exists, Otherwise returns <see cref="string.Empty"/>
/// </summary>
public string HotAddress { get; set; } = string.Empty;

/// <summary>
/// Will return the script cold public address if exists, Otherwise returns <see cref="string.Empty"/>
/// </summary>
public string ColdAddress { get; set; } = string.Empty;

}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using Blockcore.Consensus.ScriptInfo;
using Blockcore.Consensus.TransactionInfo;
using Blockcore.Consensus.TransactionInfo;
using NBitcoin;

namespace Blockcore.Features.ColdStaking
namespace Blockcore.Consensus.ScriptInfo
{
/// <summary>
/// The scriptSig parameters used for cold staking script.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
using System;
using System.Linq;
using Blockcore.Consensus;
using Blockcore.Consensus.BlockInfo;
using Blockcore.Consensus.ScriptInfo;
using Blockcore.Consensus.TransactionInfo;
using Blockcore.Networks;
using Blockcore.Utilities;
using NBitcoin;
using static Blockcore.Consensus.ScriptInfo.OpcodeType;

namespace Blockcore.Features.ColdStaking
namespace Blockcore.Consensus.ScriptInfo
{
/// <summary>
/// Script template for the cold staking script.
Expand Down
18 changes: 18 additions & 0 deletions src/Blockcore/Consensus/ScriptInfo/Script.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,24 @@ public BitcoinAddress GetDestinationAddress(Network network)
return dest == null ? null : dest.GetAddress(network);
}

/// <summary>
/// Extract ColdStakingScript addresses from scriptPubKey
/// </summary>
/// <param name="network"></param>
/// <returns>Both hot and cold <c>BitcoinAddress</c> addresses</returns>
public (BitcoinAddress hotAddress, BitcoinAddress coldAddress) GetColdStakeDestinationAddress(Network network)
{
bool hasAddresses = ColdStakingScriptTemplate.Instance.ExtractScriptPubKeyParameters(this, out KeyId hotKeyId, out KeyId coldKeyId);
if (hasAddresses)
{
return (hotKeyId.GetAddress(network), coldKeyId.GetAddress(network));
}
else
{
return (null, null);
}
}

/// <summary>
/// Extract P2SH/P2PH/P2WSH/P2WPKH id from scriptPubKey
/// </summary>
Expand Down
10 changes: 4 additions & 6 deletions src/Blockcore/Interfaces/IScriptAddressReader.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Blockcore.Consensus.ScriptInfo;
using Blockcore.Consensus;
using Blockcore.Consensus.ScriptInfo;
using Blockcore.Networks;
using NBitcoin;

Expand All @@ -12,9 +13,6 @@ public interface IScriptAddressReader
/// <summary>
/// Extracts an address from a given Script, if available. Otherwise returns <see cref="string.Empty"/>
/// </summary>
/// <param name="network"></param>
/// <param name="script"></param>
/// <returns></returns>
string GetAddressFromScriptPubKey(Network network, Script script);
ScriptAddressResult GetAddressFromScriptPubKey(Network network, Script script);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -447,15 +447,22 @@ private bool ProcessBlock(Block block, ChainedHeader header)
if (amountSpent == 0)
continue;

string address = this.scriptAddressReader.GetAddressFromScriptPubKey(this.network, new Script(consumedOutputData.ScriptPubKeyBytes));
var address = this.scriptAddressReader.GetAddressFromScriptPubKey(this.network, new Script(consumedOutputData.ScriptPubKeyBytes));

if (string.IsNullOrEmpty(address))
if (address.IsNullOrEmpty())
{
// This condition need not be logged, as the address reader should be aware of all possible address formats already.
continue;
}

this.ProcessBalanceChangeLocked(header.Height, address, amountSpent, false);
if (address.Address != string.Empty)
this.ProcessBalanceChangeLocked(header.Height, address.Address, amountSpent, false);

if (address.HotAddress != string.Empty)
this.ProcessBalanceChangeLocked(header.Height, address.HotAddress, amountSpent, false);

if (address.ColdAddress != string.Empty)
this.ProcessBalanceChangeLocked(header.Height, address.ColdAddress, amountSpent, false);
}

// Process outputs.
Expand All @@ -469,16 +476,23 @@ private bool ProcessBlock(Block block, ChainedHeader header)
if (amountReceived == 0 || txOut.IsEmpty || txOut.ScriptPubKey.IsUnspendable)
continue;

string address = this.scriptAddressReader.GetAddressFromScriptPubKey(this.network, txOut.ScriptPubKey);
var address = this.scriptAddressReader.GetAddressFromScriptPubKey(this.network, txOut.ScriptPubKey);

if (string.IsNullOrEmpty(address))
if (address.IsNullOrEmpty())
{
// This condition need not be logged, as the address reader should be aware of all
// possible address formats already.
continue;
}

this.ProcessBalanceChangeLocked(header.Height, address, amountReceived, true);
if (address.Address != string.Empty)
this.ProcessBalanceChangeLocked(header.Height, address.Address, amountReceived, true);

if (address.HotAddress != string.Empty)
this.ProcessBalanceChangeLocked(header.Height, address.HotAddress, amountReceived, true);

if (address.ColdAddress != string.Empty)
this.ProcessBalanceChangeLocked(header.Height, address.ColdAddress, amountReceived, true);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Blockcore.Configuration.Logging;
using Blockcore.Connection;
using Blockcore.Connection.Broadcasting;
using Blockcore.Consensus.ScriptInfo;
using Blockcore.Features.BlockStore;
using Blockcore.Features.MemoryPool;
using Blockcore.Features.RPC;
Expand Down