Commit 2cfa0f42 authored by Pavel Pavlov's avatar Pavel Pavlov

Modify project NBitcoin

parent 2edbb663
......@@ -16,7 +16,7 @@ namespace NBitcoin
public class Scope : IDisposable
{
Action close;
private Action close;
public Scope(Action open, Action close)
{
this.close = close;
......@@ -27,7 +27,7 @@ namespace NBitcoin
public void Dispose()
{
close();
this.close();
}
#endregion
......@@ -48,7 +48,7 @@ namespace NBitcoin
// TODO: Make NetworkOptions required in the constructors of this class.
public partial class BitcoinStream
{
int maxArraySize = 1024 * 1024;
private int maxArraySize = 1024 * 1024;
public int MaxArraySize
{
get
......@@ -62,7 +62,7 @@ namespace NBitcoin
}
//ReadWrite<T>(ref T data)
static MethodInfo readWriteTyped;
private static MethodInfo readWriteTyped;
static BitcoinStream()
{
readWriteTyped = typeof(BitcoinStream)
......@@ -95,6 +95,7 @@ namespace NBitcoin
public BitcoinStream(Stream inner, bool serializing)
{
this.ConsensusFactory = new DefaultConsensusFactory();
this.serializing = serializing;
this.inner = inner;
}
......@@ -138,12 +139,12 @@ namespace NBitcoin
{
if (this.Serializing)
{
VarString str = new VarString(bytes);
var str = new VarString(bytes);
str.ReadWrite(this);
}
else
{
VarString str = new VarString();
var str = new VarString();
str.ReadWrite(this);
bytes = str.GetString(true);
}
......@@ -193,12 +194,14 @@ namespace NBitcoin
public void ReadWrite<T>(ref T data) where T : IBitcoinSerializable
{
var obj = data;
T obj = data;
if (obj == null)
{
if (!this.ConsensusFactory.TryCreateNew<T>(out obj))
obj = this.ConsensusFactory.TryCreateNew<T>();
if (obj == null)
obj = Activator.CreateInstance<T>();
}
obj.ReadWrite(this);
if (!this.Serializing)
data = obj;
......@@ -220,7 +223,7 @@ namespace NBitcoin
where TList : List<TItem>, new()
where TItem : IBitcoinSerializable, new()
{
var dataArray = data == null ? null : data.ToArray();
TItem[] dataArray = data == null ? null : data.ToArray();
if (this.Serializing && dataArray == null)
{
......@@ -241,7 +244,7 @@ namespace NBitcoin
public void ReadWrite(ref byte[] arr)
{
this.ReadWriteBytes(ref arr);
ReadWriteBytes(ref arr);
}
public void ReadWrite(ref byte[] arr, int offset, int count)
......@@ -265,7 +268,7 @@ namespace NBitcoin
{
var bytes = new byte[size];
for(int i = 0; i < size; i++)
for (int i = 0; i < size; i++)
{
bytes[i] = (byte)(value >> i * 8);
}
......@@ -277,7 +280,7 @@ namespace NBitcoin
ulong valueTemp = 0;
for (int i = 0; i < bytes.Length; i++)
{
var v = (ulong)bytes[i];
ulong v = (ulong)bytes[i];
valueTemp += v << (i * 8);
}
value = valueTemp;
......@@ -300,7 +303,7 @@ namespace NBitcoin
}
else
{
var readen = this.Inner.ReadEx(data, offset, count, this.ReadCancellationToken);
int readen = this.Inner.ReadEx(data, offset, count, this.ReadCancellationToken);
if (readen == 0)
throw new EndOfStreamException("No more byte to read");
this.Counter.AddRead(readen);
......@@ -328,7 +331,7 @@ namespace NBitcoin
}
else
{
var readen = this.Inner.ReadByte();
int readen = this.Inner.ReadByte();
if (readen == -1)
throw new EndOfStreamException("No more byte to read");
data = (byte)readen;
......@@ -344,7 +347,7 @@ namespace NBitcoin
public IDisposable BigEndianScope()
{
var old = this.IsBigEndian;
bool old = this.IsBigEndian;
return new Scope(() =>
{
this.IsBigEndian = true;
......@@ -355,7 +358,7 @@ namespace NBitcoin
});
}
ProtocolVersion protocolVersion = ProtocolVersion.PROTOCOL_VERSION;
private ProtocolVersion protocolVersion = ProtocolVersion.PROTOCOL_VERSION;
public ProtocolVersion ProtocolVersion
{
get
......@@ -368,7 +371,7 @@ namespace NBitcoin
}
}
TransactionOptions transactionSupportedOptions = TransactionOptions.All;
private TransactionOptions transactionSupportedOptions = TransactionOptions.All;
public TransactionOptions TransactionOptions
{
get
......@@ -388,7 +391,7 @@ namespace NBitcoin
public IDisposable ProtocolVersionScope(ProtocolVersion version)
{
var old = this.ProtocolVersion;
ProtocolVersion old = this.ProtocolVersion;
return new Scope(() =>
{
this.ProtocolVersion = version;
......@@ -419,7 +422,7 @@ namespace NBitcoin
public IDisposable SerializationTypeScope(SerializationType value)
{
var old = this.Type;
SerializationType old = this.Type;
return new Scope(() =>
{
this.Type = value;
......
......@@ -23,16 +23,16 @@ namespace NBitcoin
}
// 20,000 items with fp rate < 0.1% or 10,000 items and <0.0001%
const uint MAX_BLOOM_FILTER_SIZE = 36000; // bytes
const uint MAX_HASH_FUNCS = 50;
const decimal LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455M;
const decimal LN2 = 0.6931471805599453094172321214581765680755001343602552M;
private const uint MAX_BLOOM_FILTER_SIZE = 36000; // bytes
private const uint MAX_HASH_FUNCS = 50;
private const decimal LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455M;
private const decimal LN2 = 0.6931471805599453094172321214581765680755001343602552M;
byte[] vData;
uint nHashFuncs;
uint nTweak;
byte nFlags;
private byte[] vData;
private uint nHashFuncs;
private uint nTweak;
private byte nFlags;
private bool isFull = false;
private bool isEmpty;
......@@ -48,49 +48,50 @@ namespace NBitcoin
// The ideal size for a bloom filter with a given number of elements and false positive rate is:
// - nElements * log(fp rate) / ln(2)^2
// We ignore filter parameters which will create a bloom filter larger than the protocol limits
vData = new byte[Math.Min((uint)(-1 / LN2SQUARED * nElements * (decimal)Math.Log(nFPRate)), MAX_BLOOM_FILTER_SIZE) / 8];
this.vData = new byte[Math.Min((uint)(-1 / LN2SQUARED * nElements * (decimal)Math.Log(nFPRate)), MAX_BLOOM_FILTER_SIZE) / 8];
//vData(min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8),
// The ideal number of hash functions is filter size * ln(2) / number of elements
// Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits
// See http://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas
this.nHashFuncs = Math.Min((uint)(vData.Length * 8 / nElements * LN2), MAX_HASH_FUNCS);
this.nHashFuncs = Math.Min((uint)(this.vData.Length * 8 / nElements * LN2), MAX_HASH_FUNCS);
this.nTweak = nTweakIn;
this.nFlags = (byte)nFlagsIn;
}
uint Hash(uint nHashNum, byte[] vDataToHash)
private uint Hash(uint nHashNum, byte[] vDataToHash)
{
// 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values.
return (uint)(Hashes.MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.Length * 8));
return (uint)(Hashes.MurmurHash3(nHashNum * 0xFBA4C795 + this.nTweak, vDataToHash) % (this.vData.Length * 8));
}
public void Insert(byte[] vKey)
{
if(isFull)
if(this.isFull)
return;
for(uint i = 0; i < nHashFuncs; i++)
for(uint i = 0; i < this.nHashFuncs; i++)
{
uint nIndex = Hash(i, vKey);
// Sets bit nIndex of vData
vData[nIndex >> 3] |= (byte)(1 << (7 & (int)nIndex));
this.vData[nIndex >> 3] |= (byte)(1 << (7 & (int)nIndex));
}
isEmpty = false;
this.isEmpty = false;
}
public bool Contains(byte[] vKey)
{
if(isFull)
if(this.isFull)
return true;
if(isEmpty)
if(this.isEmpty)
return false;
for(uint i = 0; i < nHashFuncs; i++)
for(uint i = 0; i < this.nHashFuncs; i++)
{
uint nIndex = Hash(i, vKey);
// Checks bit nIndex of vData
if((vData[nIndex >> 3] & (byte)(1 << (7 & (int)nIndex))) == 0)
if((this.vData[nIndex >> 3] & (byte)(1 << (7 & (int)nIndex))) == 0)
return false;
}
return true;
......@@ -125,17 +126,17 @@ namespace NBitcoin
public bool IsWithinSizeConstraints()
{
return vData.Length <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
return this.vData.Length <= MAX_BLOOM_FILTER_SIZE && this.nHashFuncs <= MAX_HASH_FUNCS;
}
#region IBitcoinSerializable Members
public void ReadWrite(BitcoinStream stream)
{
stream.ReadWriteAsVarString(ref vData);
stream.ReadWrite(ref nHashFuncs);
stream.ReadWrite(ref nTweak);
stream.ReadWrite(ref nFlags);
stream.ReadWriteAsVarString(ref this.vData);
stream.ReadWrite(ref this.nHashFuncs);
stream.ReadWrite(ref this.nTweak);
stream.ReadWrite(ref this.nFlags);
}
#endregion
......@@ -146,13 +147,13 @@ namespace NBitcoin
{
if(tx == null)
throw new ArgumentNullException("tx");
var hash = tx.GetHash();
uint256 hash = tx.GetHash();
bool fFound = false;
// Match if the filter contains the hash of tx
// for finding tx when they appear in a block
if(isFull)
if(this.isFull)
return true;
if(isEmpty)
if(this.isEmpty)
return false;
if(Contains(hash))
fFound = true;
......@@ -169,11 +170,11 @@ namespace NBitcoin
if(op.PushData != null && op.PushData.Length != 0 && Contains(op.PushData))
{
fFound = true;
if((nFlags & (byte)BloomFlags.UPDATE_MASK) == (byte)BloomFlags.UPDATE_ALL)
if((this.nFlags & (byte)BloomFlags.UPDATE_MASK) == (byte)BloomFlags.UPDATE_ALL)
Insert(new OutPoint(hash, i));
else if((nFlags & (byte)BloomFlags.UPDATE_MASK) == (byte)BloomFlags.UPDATE_P2PUBKEY_ONLY)
else if((this.nFlags & (byte)BloomFlags.UPDATE_MASK) == (byte)BloomFlags.UPDATE_P2PUBKEY_ONLY)
{
var template = StandardScripts.GetTemplateFromScriptPubKey(Network.Main, txout.ScriptPubKey); // this is only valid for Bitcoin.
ScriptTemplate template = StandardScripts.GetTemplateFromScriptPubKey(txout.ScriptPubKey); // this is only valid for Bitcoin.
if(template != null &&
(template.Type == TxOutType.TX_PUBKEY || template.Type == TxOutType.TX_MULTISIG))
Insert(new OutPoint(hash, i));
......
......@@ -8,7 +8,7 @@ namespace NBitcoin.BuilderExtensions
{
public override bool CanCombineScriptSig(Network network, Script scriptPubKey, Script a, Script b)
{
return PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(network, scriptPubKey) != null;
return PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey) != null;
}
public override bool CanDeduceScriptPubKey(Network network, Script scriptSig)
......@@ -18,31 +18,31 @@ namespace NBitcoin.BuilderExtensions
public override bool CanEstimateScriptSigSize(Network network, Script scriptPubKey)
{
return PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(network, scriptPubKey) != null;
return PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey) != null;
}
public override bool CanGenerateScriptSig(Network network, Script scriptPubKey)
{
return PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(network, scriptPubKey) != null;
return PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey) != null;
}
public override Script CombineScriptSig(Network network, Script scriptPubKey, Script a, Script b)
{
var para = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(network, scriptPubKey);
PayToMultiSigTemplateParameters para = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);
// Combine all the signatures we've got:
var aSigs = PayToMultiSigTemplate.Instance.ExtractScriptSigParameters(network, a);
TransactionSignature[] aSigs = PayToMultiSigTemplate.Instance.ExtractScriptSigParameters(network, a);
if(aSigs == null)
return b;
var bSigs = PayToMultiSigTemplate.Instance.ExtractScriptSigParameters(network, b);
TransactionSignature[] bSigs = PayToMultiSigTemplate.Instance.ExtractScriptSigParameters(network, b);
if(bSigs == null)
return a;
int sigCount = 0;
TransactionSignature[] sigs = new TransactionSignature[para.PubKeys.Length];
var sigs = new TransactionSignature[para.PubKeys.Length];
for(int i = 0; i < para.PubKeys.Length; i++)
{
var aSig = i < aSigs.Length ? aSigs[i] : null;
var bSig = i < bSigs.Length ? bSigs[i] : null;
var sig = aSig ?? bSig;
TransactionSignature aSig = i < aSigs.Length ? aSigs[i] : null;
TransactionSignature bSig = i < bSigs.Length ? bSigs[i] : null;
TransactionSignature sig = aSig ?? bSig;
if(sig != null)
{
sigs[i] = sig;
......@@ -63,15 +63,15 @@ namespace NBitcoin.BuilderExtensions
public override int EstimateScriptSigSize(Network network, Script scriptPubKey)
{
var p2mk = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(network, scriptPubKey);
PayToMultiSigTemplateParameters p2mk = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);
return PayToMultiSigTemplate.Instance.GenerateScriptSig(Enumerable.Range(0, p2mk.SignatureCount).Select(o => DummySignature).ToArray()).Length;
}
public override Script GenerateScriptSig(Network network, Script scriptPubKey, IKeyRepository keyRepo, ISigner signer)
{
var multiSigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(network, scriptPubKey);
TransactionSignature[] signatures = new TransactionSignature[multiSigParams.PubKeys.Length];
var keys =
PayToMultiSigTemplateParameters multiSigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);
var signatures = new TransactionSignature[multiSigParams.PubKeys.Length];
Key[] keys =
multiSigParams
.PubKeys
.Select(p => keyRepo.FindKey(p.ScriptPubKey))
......@@ -84,7 +84,7 @@ namespace NBitcoin.BuilderExtensions
break;
if(keys[i] != null)
{
var sig = signer.Sign(keys[i]);
TransactionSignature sig = signer.Sign(keys[i]);
signatures[i] = sig;
sigCount++;
}
......
......@@ -4,29 +4,29 @@
{
public override bool CanCombineScriptSig(Network network, Script scriptPubKey, Script a, Script b)
{
return PayToPubkeyHashTemplate.Instance.CheckScriptPubKey(network, scriptPubKey);
return PayToPubkeyHashTemplate.Instance.CheckScriptPubKey(scriptPubKey);
}
public override bool CanDeduceScriptPubKey(Network network, Script scriptSig)
{
var para = PayToPubkeyHashTemplate.Instance.ExtractScriptSigParameters(network, scriptSig);
PayToPubkeyHashScriptSigParameters para = PayToPubkeyHashTemplate.Instance.ExtractScriptSigParameters(network, scriptSig);
return para != null && para.PublicKey != null;
}
public override bool CanEstimateScriptSigSize(Network network, Script scriptPubKey)
{
return PayToPubkeyHashTemplate.Instance.CheckScriptPubKey(network, scriptPubKey);
return PayToPubkeyHashTemplate.Instance.CheckScriptPubKey(scriptPubKey);
}
public override bool CanGenerateScriptSig(Network network, Script scriptPubKey)
{
return PayToPubkeyHashTemplate.Instance.CheckScriptPubKey(network, scriptPubKey);
return PayToPubkeyHashTemplate.Instance.CheckScriptPubKey(scriptPubKey);
}
public override Script CombineScriptSig(Network network, Script scriptPubKey, Script a, Script b)
{
var aSig = PayToPubkeyHashTemplate.Instance.ExtractScriptSigParameters(network, a);
var bSig = PayToPubkeyHashTemplate.Instance.ExtractScriptSigParameters(network, b);
PayToPubkeyHashScriptSigParameters aSig = PayToPubkeyHashTemplate.Instance.ExtractScriptSigParameters(network, a);
PayToPubkeyHashScriptSigParameters bSig = PayToPubkeyHashTemplate.Instance.ExtractScriptSigParameters(network, b);
if(aSig == null)
return b;
if(bSig == null)
......@@ -39,7 +39,7 @@
public override Script DeduceScriptPubKey(Network network, Script scriptSig)
{
var p2pkh = PayToPubkeyHashTemplate.Instance.ExtractScriptSigParameters(network, scriptSig);
PayToPubkeyHashScriptSigParameters p2pkh = PayToPubkeyHashTemplate.Instance.ExtractScriptSigParameters(network, scriptSig);
return p2pkh.PublicKey.Hash.ScriptPubKey;
}
......@@ -50,11 +50,11 @@
public override Script GenerateScriptSig(Network network, Script scriptPubKey, IKeyRepository keyRepo, ISigner signer)
{
var parameters = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);
var key = keyRepo.FindKey(parameters.ScriptPubKey);
KeyId parameters = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);
Key key = keyRepo.FindKey(parameters.ScriptPubKey);
if(key == null)
return null;
var sig = signer.Sign(key);
TransactionSignature sig = signer.Sign(key);
return PayToPubkeyHashTemplate.Instance.GenerateScriptSig(sig, key.PubKey);
}
}
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NBitcoin.Protocol;
namespace NBitcoin
{
public class CachedNoSqlRepository : NoSqlRepository
{
class Raw : IBitcoinSerializable
private class Raw : IBitcoinSerializable
{
public Raw()
{
}
public Raw(byte[] data)
{
var str = new VarString();
str.FromBytes(data);
_Data = str.GetString(true);
}
private byte[] _Data = new byte[0];
public byte[] Data
{
get
{
return _Data;
return this._Data;
}
}
#region IBitcoinSerializable Members
public void ReadWrite(BitcoinStream stream)
{
stream.ReadWriteAsVarString(ref _Data);
stream.ReadWriteAsVarString(ref this._Data);
}
#endregion
}
public CachedNoSqlRepository(NoSqlRepository inner)
{
_InnerRepository = inner;
}
private readonly NoSqlRepository _InnerRepository;
public NoSqlRepository InnerRepository
{
get
public CachedNoSqlRepository(NoSqlRepository inner) : base(inner.Network)
{
return _InnerRepository;
this.InnerRepository = inner;
}
}
Dictionary<string, byte[]> _Table = new Dictionary<string, byte[]>();
HashSet<string> _Removed = new HashSet<string>();
HashSet<string> _Added = new HashSet<string>();
ReaderWriterLock @lock = new ReaderWriterLock();
public NoSqlRepository InnerRepository { get; }
private Dictionary<string, byte[]> _Table = new Dictionary<string, byte[]>();
private HashSet<string> _Removed = new HashSet<string>();
private HashSet<string> _Added = new HashSet<string>();
private ReaderWriterLock @lock = new ReaderWriterLock();
public override async Task PutBatch(IEnumerable<Tuple<string, IBitcoinSerializable>> values)
{
await base.PutBatch(values).ConfigureAwait(false);
await _InnerRepository.PutBatch(values).ConfigureAwait(false);
await this.InnerRepository.PutBatch(values).ConfigureAwait(false);
}
protected override Task PutBytesBatch(IEnumerable<Tuple<string, byte[]>> enumerable)
{
using(@lock.LockWrite())
using (this.@lock.LockWrite())
{
foreach(var data in enumerable)
foreach (Tuple<string, byte[]> data in enumerable)
{
if(data.Item2 == null)
if (data.Item2 == null)
{
_Table.Remove(data.Item1);
_Removed.Add(data.Item1);
_Added.Remove(data.Item1);
this._Table.Remove(data.Item1);
this._Removed.Add(data.Item1);
this._Added.Remove(data.Item1);
}
else
{
_Table.AddOrReplace(data.Item1, data.Item2);
_Removed.Remove(data.Item1);
_Added.Add(data.Item1);
this._Table.AddOrReplace(data.Item1, data.Item2);
this._Removed.Remove(data.Item1);
this._Added.Add(data.Item1);
}
}
}
......@@ -88,37 +77,23 @@ namespace NBitcoin
{
byte[] result = null;
bool found;
using(@lock.LockRead())
using (this.@lock.LockRead())
{
found = _Table.TryGetValue(key, out result);
found = this._Table.TryGetValue(key, out result);
}
if(!found)
if (!found)
{
var raw = await InnerRepository.GetAsync<Raw>(key).ConfigureAwait(false);
if(raw != null)
Raw raw = await this.InnerRepository.GetAsync<Raw>(key).ConfigureAwait(false);
if (raw != null)
{
result = raw.Data;
using(@lock.LockWrite())
using (this.@lock.LockWrite())
{
_Table.AddOrReplace(key, raw.Data);
this._Table.AddOrReplace(key, raw.Data);
}
}
}
return result;
}
public void Flush()
{
using(@lock.LockWrite())
{
InnerRepository
.PutBatch(_Removed.Select(k => Tuple.Create<string, IBitcoinSerializable>(k, null))
.Concat(_Added.Select(k => Tuple.Create<string, IBitcoinSerializable>(k, new Raw(_Table[k])))))
.GetAwaiter().GetResult();
_Removed.Clear();
_Added.Clear();
_Table.Clear();
}
}
}
}
\ No newline at end of file
......@@ -51,12 +51,12 @@ namespace NBitcoin
}
public IssuanceCoin(Coin bearer)
{
Bearer = bearer;
this.Bearer = bearer;
}
public IssuanceCoin(OutPoint outpoint, TxOut txout)
{
Bearer = new Coin(outpoint, txout);
this.Bearer = new Coin(outpoint, txout);
}
......@@ -64,7 +64,7 @@ namespace NBitcoin
{
get
{
return Bearer.TxOut.ScriptPubKey.Hash.ToAssetId();
return this.Bearer.TxOut.ScriptPubKey.Hash.ToAssetId();
}
}
......@@ -81,11 +81,11 @@ namespace NBitcoin
{
get
{
return Bearer.TxOut.Value;
return this.Bearer.TxOut.Value;
}
set
{
Bearer.TxOut.Value = value;
this.Bearer.TxOut.Value = value;
}
}
......@@ -93,7 +93,7 @@ namespace NBitcoin
{
get
{
return Bearer.TxOut;
return this.Bearer.TxOut;
}
}
......@@ -103,7 +103,7 @@ namespace NBitcoin
{
get
{
return Bearer.TxOut.ScriptPubKey;
return this.Bearer.TxOut.ScriptPubKey;
}
}
......@@ -121,7 +121,7 @@ namespace NBitcoin
{
get
{
return Bearer.Outpoint;
return this.Bearer.Outpoint;
}
}
......@@ -133,7 +133,7 @@ namespace NBitcoin
{
get
{
return AssetId;
return this.AssetId;
}
}
......@@ -141,7 +141,7 @@ namespace NBitcoin
{
get
{
return Bearer;
return this.Bearer;
}
}
......@@ -153,7 +153,7 @@ namespace NBitcoin
{
get
{
return Amount;
return this.Amount;
}
}
......@@ -161,7 +161,7 @@ namespace NBitcoin
{
get
{
return Outpoint;
return this.Outpoint;
}
}
......@@ -169,7 +169,7 @@ namespace NBitcoin
{
get
{
return TxOut;
return this.TxOut;
}
}
......@@ -209,8 +209,8 @@ namespace NBitcoin
}
public ColoredCoin(AssetMoney asset, Coin bearer)
{
Amount = asset;
Bearer = bearer;
this.Amount = asset;
this.Bearer = bearer;
}
public ColoredCoin(Transaction tx, ColoredEntry entry)
......@@ -226,7 +226,7 @@ namespace NBitcoin
{
get
{
return Amount.Id;
return this.Amount.Id;
}
}
......@@ -241,11 +241,11 @@ namespace NBitcoin
{
get
{
return Amount;
return this.Amount;
}
set
{
Amount = value;
this.Amount = value;
}
}
......@@ -259,7 +259,7 @@ namespace NBitcoin
{
get
{
return Bearer.TxOut;
return this.Bearer.TxOut;
}
}
......@@ -269,7 +269,7 @@ namespace NBitcoin
{
get
{
return Bearer.Outpoint;
return this.Bearer.Outpoint;
}
}
......@@ -277,7 +277,7 @@ namespace NBitcoin
{
get
{
return Bearer.ScriptPubKey;
return this.Bearer.ScriptPubKey;
}
}
......@@ -295,9 +295,9 @@ namespace NBitcoin
throw new ArgumentNullException("tx");
if(txId == null)
txId = tx.GetHash();
foreach(var entry in colored.Issuances.Concat(colored.Transfers))
foreach(ColoredEntry entry in colored.Issuances.Concat(colored.Transfers))
{
var txout = tx.Outputs[entry.Index];
TxOut txout = tx.Outputs[entry.Index];
yield return new ColoredCoin(entry.Asset, new Coin(new OutPoint(txId, entry.Index), txout));
}
}
......@@ -310,7 +310,7 @@ namespace NBitcoin
{
if(txId == null)
txId = tx.GetHash();
var colored = tx.GetColoredTransaction(repo);
ColoredTransaction colored = tx.GetColoredTransaction(repo);
return Find(txId, tx, colored);
}
......@@ -320,7 +320,7 @@ namespace NBitcoin
{
get
{
return AssetId;
return this.AssetId;
}
}
......@@ -328,7 +328,7 @@ namespace NBitcoin
{
get
{
return Bearer;
return this.Bearer;
}
}
......@@ -340,7 +340,7 @@ namespace NBitcoin
{
get
{
return Amount;
return this.Amount;
}
}
......@@ -348,7 +348,7 @@ namespace NBitcoin
{
get
{
return Outpoint;
return this.Outpoint;
}
}
......@@ -356,7 +356,7 @@ namespace NBitcoin
{
get
{
return TxOut;
return this.TxOut;
}
}
......@@ -390,16 +390,16 @@ namespace NBitcoin
}
public Coin(OutPoint fromOutpoint, TxOut fromTxOut)
{
Outpoint = fromOutpoint;
TxOut = fromTxOut;
this.Outpoint = fromOutpoint;
this.TxOut = fromTxOut;
}
public Coin(Transaction fromTx, uint fromOutputIndex)
{
if(fromTx == null)
throw new ArgumentNullException("fromTx");
Outpoint = new OutPoint(fromTx, fromOutputIndex);
TxOut = fromTx.Outputs[fromOutputIndex];
this.Outpoint = new OutPoint(fromTx, fromOutputIndex);
this.TxOut = fromTx.Outputs[fromOutputIndex];
}
public Coin(Transaction fromTx, TxOut fromOutput)
......@@ -408,42 +408,42 @@ namespace NBitcoin
throw new ArgumentNullException("fromTx");
if(fromOutput == null)
throw new ArgumentNullException("fromOutput");
uint outputIndex = (uint)fromTx.Outputs.FindIndex(r => Object.ReferenceEquals(fromOutput, r));
Outpoint = new OutPoint(fromTx, outputIndex);
TxOut = fromOutput;
uint outputIndex = (uint)fromTx.Outputs.FindIndex(r => ReferenceEquals(fromOutput, r));
this.Outpoint = new OutPoint(fromTx, outputIndex);
this.TxOut = fromOutput;
}
public Coin(IndexedTxOut txOut)
{
Outpoint = new OutPoint(txOut.Transaction.GetHash(), txOut.N);
TxOut = txOut.TxOut;
this.Outpoint = new OutPoint(txOut.Transaction.GetHash(), txOut.N);
this.TxOut = txOut.TxOut;
}
public Coin(uint256 fromTxHash, uint fromOutputIndex, Money amount, Script scriptPubKey)
{
Outpoint = new OutPoint(fromTxHash, fromOutputIndex);
TxOut = new TxOut(amount, scriptPubKey);
this.Outpoint = new OutPoint(fromTxHash, fromOutputIndex);
this.TxOut = new TxOut(amount, scriptPubKey);
}
public virtual Script GetScriptCode(Network network)
{
if(!CanGetScriptCode(network))
throw new InvalidOperationException("You need to provide P2WSH or P2SH redeem script with Coin.ToScriptCoin()");
if(_OverrideScriptCode != null)
return _OverrideScriptCode;
var key = PayToWitPubKeyHashTemplate.Instance.ExtractScriptPubKeyParameters(network, ScriptPubKey);
if(this._OverrideScriptCode != null)
return this._OverrideScriptCode;
WitKeyId key = PayToWitPubKeyHashTemplate.Instance.ExtractScriptPubKeyParameters(network, this.ScriptPubKey);
if(key != null)
return key.AsKeyId().ScriptPubKey;
return ScriptPubKey;
return this.ScriptPubKey;
}
public virtual bool CanGetScriptCode(Network network)
{
return _OverrideScriptCode != null || !ScriptPubKey.IsPayToScriptHash(network) && !PayToWitScriptHashTemplate.Instance.CheckScriptPubKey(network, ScriptPubKey);
return this._OverrideScriptCode != null || !this.ScriptPubKey.IsPayToScriptHash(network) && !PayToWitScriptHashTemplate.Instance.CheckScriptPubKey(this.ScriptPubKey);
}
public virtual HashVersion GetHashVersion(Network network)
{
if(PayToWitTemplate.Instance.CheckScriptPubKey(network, ScriptPubKey))
if(PayToWitTemplate.Instance.CheckScriptPubKey(this.ScriptPubKey))
return HashVersion.Witness;
return HashVersion.Original;
}
......@@ -489,27 +489,26 @@ namespace NBitcoin
{
get
{
if(TxOut == null)
if(this.TxOut == null)
return Money.Zero;
return TxOut.Value;
return this.TxOut.Value;
}
set
{
EnsureTxOut();
TxOut.Value = value;
this.TxOut.Value = value;
}
}
private void EnsureTxOut()
{
if(TxOut == null)
TxOut = new TxOut();
if(this.TxOut == null) this.TxOut = new TxOut();
}
protected Script _OverrideScriptCode;
public void OverrideScriptCode(Script scriptCode)
{
_OverrideScriptCode = scriptCode;
this._OverrideScriptCode = scriptCode;
}
#endregion
......@@ -518,14 +517,14 @@ namespace NBitcoin
{
get
{
if(TxOut == null)
if(this.TxOut == null)
return Script.Empty;
return TxOut.ScriptPubKey;
return this.TxOut.ScriptPubKey;
}
set
{
EnsureTxOut();
TxOut.ScriptPubKey = value;
this.TxOut.ScriptPubKey = value;
}
}
......@@ -535,7 +534,7 @@ namespace NBitcoin
{
get
{
return Amount;
return this.Amount;
}
}
......@@ -543,7 +542,7 @@ namespace NBitcoin
{
get
{
return Outpoint;
return this.Outpoint;
}
}
......@@ -551,7 +550,7 @@ namespace NBitcoin
{
get
{
return TxOut;
return this.TxOut;
}
}
......@@ -576,40 +575,40 @@ namespace NBitcoin
}
internal ScriptCoin(OutPoint fromOutpoint, TxOut fromTxOut, Script redeem)
public ScriptCoin(OutPoint fromOutpoint, TxOut fromTxOut, Script redeem)
: base(fromOutpoint, fromTxOut)
{
Redeem = redeem;
this.Redeem = redeem;
}
internal ScriptCoin(Transaction fromTx, uint fromOutputIndex, Script redeem)
: base(fromTx, fromOutputIndex)
{
Redeem = redeem;
this.Redeem = redeem;
}
internal ScriptCoin(Transaction fromTx, TxOut fromOutput, Script redeem)
: base(fromTx, fromOutput)
{
Redeem = redeem;
this.Redeem = redeem;
}
internal ScriptCoin(ICoin coin, Script redeem)
: base(coin.Outpoint, coin.TxOut)
{
Redeem = redeem;
this.Redeem = redeem;
}
internal ScriptCoin(IndexedTxOut txOut, Script redeem)
: base(txOut)
{
Redeem = redeem;
this.Redeem = redeem;
}
internal ScriptCoin(uint256 txHash, uint outputIndex, Money amount, Script scriptPubKey, Script redeem)
: base(txHash, outputIndex, amount, scriptPubKey)
{
Redeem = redeem;
this.Redeem = redeem;
}
public static ScriptCoin Create(Network network, OutPoint fromOutpoint, TxOut fromTxOut, Script redeem)
......@@ -646,16 +645,16 @@ namespace NBitcoin
{
get
{
return ScriptPubKey.ToBytes(true)[0] == (byte)OpcodeType.OP_HASH160;
return this.ScriptPubKey.ToBytes(true)[0] == (byte)OpcodeType.OP_HASH160;
}
}
public Script GetP2SHRedeem()
{
if(!IsP2SH)
if(!this.IsP2SH)
return null;
var p2shRedeem = RedeemType == RedeemType.P2SH ? Redeem :
RedeemType == RedeemType.WitnessV0 ? Redeem.WitHash.ScriptPubKey :
Script p2shRedeem = this.RedeemType == RedeemType.P2SH ? this.Redeem :
this.RedeemType == RedeemType.WitnessV0 ? this.Redeem.WitHash.ScriptPubKey :
null;
if(p2shRedeem == null)
throw new NotSupportedException("RedeemType not supported for getting the P2SH script, contact the library author");
......@@ -666,8 +665,7 @@ namespace NBitcoin
{
get
{
return
Redeem.Hash.ScriptPubKey == TxOut.ScriptPubKey ?
return this.Redeem.Hash.ScriptPubKey == this.TxOut.ScriptPubKey ?
RedeemType.P2SH :
RedeemType.WitnessV0;
}
......@@ -675,30 +673,30 @@ namespace NBitcoin
public ScriptCoin AssertCoherent(Network network)
{
if(Redeem == null)
if(this.Redeem == null)
throw new ArgumentException("redeem cannot be null", "redeem");
var expectedDestination = GetRedeemHash(network, TxOut.ScriptPubKey);
TxDestination expectedDestination = GetRedeemHash(network, this.TxOut.ScriptPubKey);
if(expectedDestination == null)
{
throw new ArgumentException("the provided scriptPubKey is not P2SH or P2WSH");
}
if(expectedDestination is ScriptId)
{
if(PayToWitScriptHashTemplate.Instance.CheckScriptPubKey(network, Redeem))
if(PayToWitScriptHashTemplate.Instance.CheckScriptPubKey(this.Redeem))
{
throw new ArgumentException("The redeem script provided must be the witness one, not the P2SH one");
}
if(expectedDestination.ScriptPubKey != Redeem.Hash.ScriptPubKey)
if(expectedDestination.ScriptPubKey != this.Redeem.Hash.ScriptPubKey)
{
if(Redeem.WitHash.ScriptPubKey.Hash.ScriptPubKey != expectedDestination.ScriptPubKey)
if(this.Redeem.WitHash.ScriptPubKey.Hash.ScriptPubKey != expectedDestination.ScriptPubKey)
throw new ArgumentException("The redeem provided does not match the scriptPubKey of the coin");
}
}
else if(expectedDestination is WitScriptId)
{
if(expectedDestination.ScriptPubKey != Redeem.WitHash.ScriptPubKey)
if(expectedDestination.ScriptPubKey != this.Redeem.WitHash.ScriptPubKey)
throw new ArgumentException("The redeem provided does not match the scriptPubKey of the coin");
}
else
......@@ -718,24 +716,23 @@ namespace NBitcoin
{
if(!CanGetScriptCode(network))
throw new InvalidOperationException("You need to provide the P2WSH redeem script with ScriptCoin.ToScriptCoin()");
if(_OverrideScriptCode != null)
return _OverrideScriptCode;
var key = PayToWitPubKeyHashTemplate.Instance.ExtractScriptPubKeyParameters(network, Redeem);
if(this._OverrideScriptCode != null)
return this._OverrideScriptCode;
WitKeyId key = PayToWitPubKeyHashTemplate.Instance.ExtractScriptPubKeyParameters(network, this.Redeem);
if(key != null)
return key.AsKeyId().ScriptPubKey;
return Redeem;
return this.Redeem;
}
public override bool CanGetScriptCode(Network network)
{
return _OverrideScriptCode != null || !IsP2SH || !PayToWitScriptHashTemplate.Instance.CheckScriptPubKey(network, Redeem);
return this._OverrideScriptCode != null || !this.IsP2SH || !PayToWitScriptHashTemplate.Instance.CheckScriptPubKey(this.Redeem);
}
public override HashVersion GetHashVersion(Network network)
{
var isWitness = PayToWitTemplate.Instance.CheckScriptPubKey(network, ScriptPubKey) ||
PayToWitTemplate.Instance.CheckScriptPubKey(network, Redeem) ||
RedeemType == NBitcoin.RedeemType.WitnessV0;
bool isWitness = PayToWitTemplate.Instance.CheckScriptPubKey(this.ScriptPubKey) ||
PayToWitTemplate.Instance.CheckScriptPubKey(this.Redeem) || this.RedeemType == RedeemType.WitnessV0;
return isWitness ? HashVersion.Witness : HashVersion.Original;
}
......@@ -762,9 +759,9 @@ namespace NBitcoin
public StealthCoin(OutPoint outpoint, TxOut txOut, Script redeem, StealthMetadata stealthMetadata, BitcoinStealthAddress address)
: base(outpoint, txOut)
{
StealthMetadata = stealthMetadata;
Address = address;
Redeem = redeem;
this.StealthMetadata = stealthMetadata;
this.Address = address;
this.Redeem = redeem;
}
public StealthMetadata StealthMetadata
{
......@@ -786,20 +783,20 @@ namespace NBitcoin
public override Script GetScriptCode(Network network)
{
if(_OverrideScriptCode != null)
return _OverrideScriptCode;
if(Redeem == null)
if(this._OverrideScriptCode != null)
return this._OverrideScriptCode;
if(this.Redeem == null)
return base.GetScriptCode(network);
else
return ScriptCoin.Create(network, this, Redeem).GetScriptCode(network);
return ScriptCoin.Create(network, this, this.Redeem).GetScriptCode(network);
}
public override HashVersion GetHashVersion(Network network)
{
if(Redeem == null)
if(this.Redeem == null)
return base.GetHashVersion(network);
else
return ScriptCoin.Create(network, this, Redeem).GetHashVersion(network);
return ScriptCoin.Create(network, this, this.Redeem).GetHashVersion(network);
}
/// <summary>
......@@ -811,17 +808,17 @@ namespace NBitcoin
/// <returns></returns>
public static StealthCoin Find(Transaction tx, BitcoinStealthAddress address, Key scan)
{
var payment = address.GetPayments(tx, scan).FirstOrDefault();
StealthPayment payment = address.GetPayments(tx, scan).FirstOrDefault();
if(payment == null)
return null;
var txId = tx.GetHash();
var txout = tx.Outputs.First(o => o.ScriptPubKey == payment.ScriptPubKey);
uint256 txId = tx.GetHash();
TxOut txout = tx.Outputs.First(o => o.ScriptPubKey == payment.ScriptPubKey);
return new StealthCoin(new OutPoint(txId, tx.Outputs.IndexOf(txout)), txout, payment.Redeem, payment.Metadata, address);
}
public StealthPayment GetPayment()
{
return new StealthPayment(TxOut.ScriptPubKey, Redeem, StealthMetadata);
return new StealthPayment(this.TxOut.ScriptPubKey, this.Redeem, this.StealthMetadata);
}
public PubKey[] Uncover(PubKey[] spendPubKeys, Key scanKey)
......@@ -829,7 +826,7 @@ namespace NBitcoin
var pubKeys = new PubKey[spendPubKeys.Length];
for(int i = 0; i < pubKeys.Length; i++)
{
pubKeys[i] = spendPubKeys[i].UncoverReceiver(scanKey, StealthMetadata.EphemKey);
pubKeys[i] = spendPubKeys[i].UncoverReceiver(scanKey, this.StealthMetadata.EphemKey);
}
return pubKeys;
}
......@@ -839,7 +836,7 @@ namespace NBitcoin
var keys = new Key[spendKeys.Length];
for(int i = 0; i < keys.Length; i++)
{
keys[i] = spendKeys[i].Uncover(scanKey, StealthMetadata.EphemKey);
keys[i] = spendKeys[i].Uncover(scanKey, this.StealthMetadata.EphemKey);
}
return keys;
}
......
using System;
namespace NBitcoin
{
/// <summary>
/// A default object factory to create instances that is not block, block header or transaction.
/// </summary>
public sealed class DefaultConsensusFactory : ConsensusFactory
{
/// <inheritdoc/>
public override T TryCreateNew<T>()
{
if (this.IsBlock<T>() || this.IsBlockHeader<T>() || this.IsTransaction<T>())
throw new Exception(string.Format("{0} cannot be created by this consensus factory, please use the appropriate one.", typeof(T).Name));
return default(T);
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Text;
using NBitcoin.BouncyCastle.Math;
using NBitcoin.DataEncoders;
namespace NBitcoin.Networks
{
class DeStreamRegTest
public class DeStreamRegTest : Network
{
public DeStreamRegTest()
{
// TODO: move this to Networks
var messageStart = new byte[4];
messageStart[0] = 0xcd;
messageStart[1] = 0xf2;
messageStart[2] = 0xc0;
messageStart[3] = 0xef;
var magic = BitConverter.ToUInt32(messageStart, 0); // 0xefc0f2cd
this.Name = "DeStreamRegTest";
this.RootFolderName = DeStreamRootFolderName;
this.DefaultConfigFilename = DeStreamDefaultConfigFilename;
this.Magic = magic;
this.DefaultPort = 18444;
this.RPCPort = 18442;
this.MaxTimeOffsetSeconds = StratisMaxTimeOffsetSeconds;
this.MaxTipAge = StratisDefaultMaxTipAgeInSeconds;
this.Consensus.SubsidyHalvingInterval = 210000;
this.Consensus.MajorityEnforceBlockUpgrade = 750;
this.Consensus.MajorityRejectBlockOutdated = 950;
this.Consensus.MajorityWindow = 1000;
this.Consensus.BuriedDeployments[BuriedDeployments.BIP34] = 0;
this.Consensus.BuriedDeployments[BuriedDeployments.BIP65] = 0;
this.Consensus.BuriedDeployments[BuriedDeployments.BIP66] = 0;
this.Consensus.BIP34Hash = new uint256("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
this.Consensus.PowLimit = new Target(uint256.Parse("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
this.Consensus.PowTargetTimespan = TimeSpan.FromSeconds(14 * 24 * 60 * 60); // two weeks
this.Consensus.PowTargetSpacing = TimeSpan.FromSeconds(10 * 60);
this.Consensus.PowAllowMinDifficultyBlocks = true;
this.Consensus.PowNoRetargeting = true;
this.Consensus.RuleChangeActivationThreshold = 1916; // 95% of 2016
this.Consensus.MinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
this.Consensus.LastPOWBlock = 12500;
this.Consensus.IsProofOfStake = true;
this.Consensus.ConsensusFactory = new PosConsensusFactory() { Consensus = this.Consensus };
this.Consensus.ProofOfStakeLimit = new BigInteger(uint256.Parse("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").ToBytes(false));
this.Consensus.ProofOfStakeLimitV2 = new BigInteger(uint256.Parse("000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff").ToBytes(false));
this.Consensus.CoinType = 105;
this.Consensus.DefaultAssumeValid = null; // turn off assumevalid for regtest.
Block genesis = CreateStratisGenesisBlock(this.Consensus.ConsensusFactory, 1470467000, 1831645, 0x1e0fffff, 1, Money.Zero);
genesis.Header.Time = 1494909211;
genesis.Header.Nonce = 2433759;
genesis.Header.Bits = this.Consensus.PowLimit;
this.Genesis = genesis;
this.Consensus.HashGenesisBlock = genesis.GetHash();
Assert(this.Consensus.HashGenesisBlock == uint256.Parse("0x93925104d664314f581bc7ecb7b4bad07bcfabd1cfce4256dbd2faddcf53bd1f"));
this.Base58Prefixes[(int)Base58Type.PUBKEY_ADDRESS] = new byte[] { (65) };
this.Base58Prefixes[(int)Base58Type.SCRIPT_ADDRESS] = new byte[] { (196) };
this.Base58Prefixes[(int)Base58Type.SECRET_KEY] = new byte[] { (65 + 128) };
this.Base58Prefixes[(int)Base58Type.ENCRYPTED_SECRET_KEY_NO_EC] = new byte[] { 0x01, 0x42 };
this.Base58Prefixes[(int)Base58Type.ENCRYPTED_SECRET_KEY_EC] = new byte[] { 0x01, 0x43 };
this.Base58Prefixes[(int)Base58Type.EXT_PUBLIC_KEY] = new byte[] { (0x04), (0x88), (0xB2), (0x1E) };
this.Base58Prefixes[(int)Base58Type.EXT_SECRET_KEY] = new byte[] { (0x04), (0x88), (0xAD), (0xE4) };
this.Base58Prefixes[(int)Base58Type.PASSPHRASE_CODE] = new byte[] { 0x2C, 0xE9, 0xB3, 0xE1, 0xFF, 0x39, 0xE2 };
this.Base58Prefixes[(int)Base58Type.CONFIRMATION_CODE] = new byte[] { 0x64, 0x3B, 0xF6, 0xA8, 0x9A };
this.Base58Prefixes[(int)Base58Type.STEALTH_ADDRESS] = new byte[] { 0x2a };
this.Base58Prefixes[(int)Base58Type.ASSET_ID] = new byte[] { 23 };
this.Base58Prefixes[(int)Base58Type.COLORED_ADDRESS] = new byte[] { 0x13 };
var encoder = new Bech32Encoder("bc");
this.Bech32Encoders[(int)Bech32Type.WITNESS_PUBKEY_ADDRESS] = encoder;
this.Bech32Encoders[(int)Bech32Type.WITNESS_SCRIPT_ADDRESS] = encoder;
}
}
}
......@@ -34,7 +34,7 @@ namespace NBitcoin.Networks
this.FallbackFee = 60000;
this.MinRelayTxFee = 10000;
this..Consensus.SubsidyHalvingInterval = 210000;
this.Consensus.SubsidyHalvingInterval = 210000;
this.Consensus.MajorityEnforceBlockUpgrade = 750;
this.Consensus.MajorityRejectBlockOutdated = 950;
this.Consensus.MajorityWindow = 1000;
......@@ -51,7 +51,7 @@ namespace NBitcoin.Networks
this.Consensus.MinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
this.Consensus.LastPOWBlock = 12500;
this.Consensus.IsProofOfStake = true;
this.Consensus.ConsensusFactory = new PosConsensusFactory() { Consensus = network.Consensus };
this.Consensus.ConsensusFactory = new PosConsensusFactory() { Consensus = this.Consensus };
this.Consensus.ProofOfStakeLimit = new BigInteger(uint256.Parse("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").ToBytes(false));
this.Consensus.ProofOfStakeLimitV2 = new BigInteger(uint256.Parse("000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff").ToBytes(false));
this.Consensus.CoinType = 105;
......
......@@ -7,16 +7,16 @@ namespace NBitcoin
{
public abstract class NoSqlRepository
{
private readonly Network network;
public readonly Network Network;
protected NoSqlRepository(Network network = null)
protected NoSqlRepository(Network network)
{
this.network = network ?? Network.Main;
this.Network = network;
}
public Task PutAsync(string key, IBitcoinSerializable obj)
{
return PutBytes(key, obj == null ? null : obj.ToBytes(network: this.network));
return PutBytes(key, obj == null ? null : obj.ToBytes(this.Network.Consensus.ConsensusFactory));
}
public void Put(string key, IBitcoinSerializable obj)
......@@ -26,12 +26,13 @@ namespace NBitcoin
public async Task<T> GetAsync<T>(string key) where T : IBitcoinSerializable, new()
{
var data = await GetBytes(key).ConfigureAwait(false);
if(data == null)
byte[] data = await GetBytes(key).ConfigureAwait(false);
if (data == null)
return default(T);
if (!this.network.Consensus.ConsensusFactory.TryCreateNew<T>(out T obj))
T obj = this.Network.Consensus.ConsensusFactory.TryCreateNew<T>();
if (obj == null)
obj = Activator.CreateInstance<T>();
obj.ReadWrite(data, network: this.network);
obj.ReadWrite(data, consensusFactory: this.Network.Consensus.ConsensusFactory);
return obj;
}
......
......@@ -11,13 +11,13 @@ namespace NBitcoin.Policy
public StandardTransactionPolicy(Network network)
{
this.network = network;
ScriptVerify = NBitcoin.ScriptVerify.Standard;
MaxTransactionSize = 100000;
this.ScriptVerify = NBitcoin.ScriptVerify.Standard;
this.MaxTransactionSize = 100000;
// TODO: replace fee params with whats in Network.
MaxTxFee = new FeeRate(Money.Coins(0.1m));
MinRelayTxFee = new FeeRate(Money.Satoshis(5000)); // TODO: new FeeRate(Money.Satoshis(network.MinRelayTxFee));
CheckFee = true;
CheckScriptPubKey = true;
this.MaxTxFee = new FeeRate(Money.Coins(0.1m));
this.MinRelayTxFee = new FeeRate(Money.Satoshis(5000)); // TODO: new FeeRate(Money.Satoshis(network.MinRelayTxFee));
this.CheckFee = true;
this.CheckScriptPubKey = true;
}
public int? MaxTransactionSize
......@@ -56,118 +56,118 @@ namespace NBitcoin.Policy
get;
set;
}
#if !NOCONSENSUSLIB
public bool UseConsensusLib
{
get;
set;
}
#endif
public const int MaxScriptSigLength = 1650;
#region ITransactionPolicy Members
public TransactionPolicyError[] Check(Transaction transaction, ICoin[] spentCoins)
{
if(transaction == null)
if (transaction == null)
throw new ArgumentNullException("transaction");
spentCoins = spentCoins ?? new ICoin[0];
List<TransactionPolicyError> errors = new List<TransactionPolicyError>();
var errors = new List<TransactionPolicyError>();
foreach(var input in transaction.Inputs.AsIndexedInputs())
foreach (IndexedTxIn input in transaction.Inputs.AsIndexedInputs())
{
var coin = spentCoins.FirstOrDefault(s => s.Outpoint == input.PrevOut);
if(coin != null)
ICoin coin = spentCoins.FirstOrDefault(s => s.Outpoint == input.PrevOut);
if (coin != null)
{
if(ScriptVerify != null)
if (this.ScriptVerify != null)
{
ScriptError error;
if(!this.VerifyScript(input, coin.TxOut.ScriptPubKey, coin.TxOut.Value, ScriptVerify.Value, out error))
if (!VerifyScript(input, coin.TxOut.ScriptPubKey, coin.TxOut.Value, this.ScriptVerify.Value, out error))
{
errors.Add(new ScriptPolicyError(input, error, ScriptVerify.Value, coin.TxOut.ScriptPubKey));
errors.Add(new ScriptPolicyError(input, error, this.ScriptVerify.Value, coin.TxOut.ScriptPubKey));
}
}
}
var txin = input.TxIn;
if(txin.ScriptSig.Length > MaxScriptSigLength)
TxIn txin = input.TxIn;
if (txin.ScriptSig.Length > MaxScriptSigLength)
{
errors.Add(new InputPolicyError("Max scriptSig length exceeded actual is " + txin.ScriptSig.Length + ", max is " + MaxScriptSigLength, input));
}
if(!txin.ScriptSig.IsPushOnly)
if (!txin.ScriptSig.IsPushOnly)
{
errors.Add(new InputPolicyError("All operation should be push", input));
}
if(!txin.ScriptSig.HasCanonicalPushes)
if (!txin.ScriptSig.HasCanonicalPushes)
{
errors.Add(new InputPolicyError("All operation should be canonical push", input));
}
}
if(CheckMalleabilitySafe)
if (this.CheckMalleabilitySafe)
{
foreach(var input in transaction.Inputs.AsIndexedInputs())
foreach (IndexedTxIn input in transaction.Inputs.AsIndexedInputs())
{
var coin = spentCoins.FirstOrDefault(s => s.Outpoint == input.PrevOut);
if(coin != null && coin.GetHashVersion(this.network) != HashVersion.Witness)
ICoin coin = spentCoins.FirstOrDefault(s => s.Outpoint == input.PrevOut);
if (coin != null && coin.GetHashVersion(this.network) != HashVersion.Witness)
errors.Add(new InputPolicyError("Malleable input detected", input));
}
}
if(CheckScriptPubKey)
if (this.CheckScriptPubKey)
{
foreach(var txout in transaction.Outputs.AsCoins())
foreach (Coin txout in transaction.Outputs.AsCoins())
{
var template = StandardScripts.GetTemplateFromScriptPubKey(this.network, txout.ScriptPubKey);
if(template == null)
ScriptTemplate template = StandardScripts.GetTemplateFromScriptPubKey(txout.ScriptPubKey);
if (template == null)
errors.Add(new OutputPolicyError("Non-Standard scriptPubKey", (int)txout.Outpoint.N));
}
}
int txSize = transaction.GetSerializedSize();
if(MaxTransactionSize != null)
if (this.MaxTransactionSize != null)
{
if(txSize >= MaxTransactionSize.Value)
errors.Add(new TransactionSizePolicyError(txSize, MaxTransactionSize.Value));
if (txSize >= this.MaxTransactionSize.Value)
errors.Add(new TransactionSizePolicyError(txSize, this.MaxTransactionSize.Value));
}
var fees = transaction.GetFee(spentCoins);
if(fees != null)
Money fees = transaction.GetFee(spentCoins);
if (fees != null)
{
if(CheckFee)
if (this.CheckFee)
{
if(MaxTxFee != null)
if (this.MaxTxFee != null)
{
var max = MaxTxFee.GetFee(txSize);
if(fees > max)
Money max = this.MaxTxFee.GetFee(txSize);
if (fees > max)
errors.Add(new FeeTooHighPolicyError(fees, max));
}
if(MinRelayTxFee != null)
if (this.MinRelayTxFee != null)
{
if(MinRelayTxFee != null)
if (this.MinRelayTxFee != null)
{
var min = MinRelayTxFee.GetFee(txSize);
if(fees < min)
Money min = this.MinRelayTxFee.GetFee(txSize);
if (fees < min)
errors.Add(new FeeTooLowPolicyError(fees, min));
}
}
}
}
if(MinRelayTxFee != null)
if (this.MinRelayTxFee != null)
{
foreach(var output in transaction.Outputs)
foreach (TxOut output in transaction.Outputs)
{
var bytes = output.ScriptPubKey.ToBytes(true);
if(output.IsDust(MinRelayTxFee) && !IsOpReturn(bytes))
errors.Add(new DustPolicyError(output.Value, output.GetDustThreshold(MinRelayTxFee)));
byte[] bytes = output.ScriptPubKey.ToBytes(true);
if (output.IsDust(this.MinRelayTxFee) && !IsOpReturn(bytes))
errors.Add(new DustPolicyError(output.Value, output.GetDustThreshold(this.MinRelayTxFee)));
}
}
var opReturnCount = transaction.Outputs.Select(o => o.ScriptPubKey.ToBytes(true)).Count(b => IsOpReturn(b));
if(opReturnCount > 1)
int opReturnCount = transaction.Outputs.Select(o => o.ScriptPubKey.ToBytes(true)).Count(b => IsOpReturn(b));
if (opReturnCount > 1)
errors.Add(new TransactionPolicyError("More than one op return detected"));
return errors.ToArray();
}
......@@ -179,17 +179,14 @@ namespace NBitcoin.Policy
private bool VerifyScript(IndexedTxIn input, Script scriptPubKey, Money value, ScriptVerify scriptVerify, out ScriptError error)
{
#if !NOCONSENSUSLIB
if(!UseConsensusLib)
#endif
if (!this.UseConsensusLib)
return input.VerifyScript(this.network, scriptPubKey, value, scriptVerify, out error);
#if !NOCONSENSUSLIB
else
{
var ok = Script.VerifyScriptConsensus(scriptPubKey, input.Transaction, input.Index, scriptVerify);
if(!ok)
bool ok = Script.VerifyScriptConsensus(scriptPubKey, input.Transaction, input.Index, scriptVerify);
if (!ok)
{
if(input.VerifyScript(this.network, scriptPubKey, scriptVerify, out error))
if (input.VerifyScript(this.network, scriptPubKey, scriptVerify, out error))
error = ScriptError.UnknownError;
return false;
}
......@@ -199,7 +196,6 @@ namespace NBitcoin.Policy
}
return true;
}
#endif
}
#endregion
......@@ -208,16 +204,14 @@ namespace NBitcoin.Policy
{
return new StandardTransactionPolicy(this.network)
{
MaxTransactionSize = MaxTransactionSize,
MaxTxFee = MaxTxFee,
MinRelayTxFee = MinRelayTxFee,
ScriptVerify = ScriptVerify,
#if !NOCONSENSUSLIB
UseConsensusLib = UseConsensusLib,
#endif
CheckMalleabilitySafe = CheckMalleabilitySafe,
CheckScriptPubKey = CheckScriptPubKey,
CheckFee = CheckFee
MaxTransactionSize = this.MaxTransactionSize,
MaxTxFee = this.MaxTxFee,
MinRelayTxFee = this.MinRelayTxFee,
ScriptVerify = this.ScriptVerify,
UseConsensusLib = this.UseConsensusLib,
CheckMalleabilitySafe = this.CheckMalleabilitySafe,
CheckScriptPubKey = this.CheckScriptPubKey,
CheckFee = this.CheckFee
};
}
......
#if !NOHTTPCLIENT
using System;
using System;
using System.Net.Http;
using System.Threading.Tasks;
......@@ -7,14 +6,8 @@ namespace NBitcoin
{
public class QBitNinjaTransactionRepository : ITransactionRepository
{
private readonly Uri _BaseUri;
public Uri BaseUri
{
get
{
return _BaseUri;
}
}
public readonly Uri BaseUri;
private readonly Network network;
/// <summary>
/// Use qbitninja public servers
......@@ -22,38 +15,35 @@ namespace NBitcoin
/// <param name="network"></param>
public QBitNinjaTransactionRepository(Network network)
{
if(network == null)
throw new ArgumentNullException("network");
_BaseUri = new Uri("http://" + (network == Network.Main ? "" : "t") + "api.qbit.ninja/");
this.network = network ?? throw new ArgumentNullException("network");
this.BaseUri = new Uri("http://" + (network == Network.Main ? "" : "t") + "api.qbit.ninja/");
}
public QBitNinjaTransactionRepository(Uri baseUri)
: this(baseUri.AbsoluteUri)
{
}
public QBitNinjaTransactionRepository(string baseUri)
{
if(!baseUri.EndsWith("/"))
baseUri += "/";
_BaseUri = new Uri(baseUri, UriKind.Absolute);
}
#region ITransactionRepository Members
this.BaseUri = new Uri(baseUri, UriKind.Absolute);
}
public async Task<Transaction> GetAsync(uint256 txId)
{
using(HttpClient client = new HttpClient())
using(var client = new HttpClient())
{
var tx = await client.GetAsync(BaseUri.AbsoluteUri + "transactions/" + txId + "?format=raw").ConfigureAwait(false);
HttpResponseMessage tx = await client.GetAsync(this.BaseUri.AbsoluteUri + "transactions/" + txId + "?format=raw").ConfigureAwait(false);
if(tx.StatusCode == System.Net.HttpStatusCode.NotFound)
return null;
tx.EnsureSuccessStatusCode();
var bytes = await tx.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
return new Transaction(bytes);
byte[] bytes = await tx.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
return this.network.CreateTransaction(bytes);
}
}
......@@ -61,8 +51,5 @@ namespace NBitcoin
{
return Task.FromResult(false);
}
#endregion
}
}
\ No newline at end of file
#endif
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Text;
namespace NBitcoin.RPC
{
public class AddressGrouping
{
public AddressGrouping()
{
this.ChangeAddresses = new List<ChangeAddress>();
}
public BitcoinAddress PublicAddress { get; set; }
public Money Amount { get; set; }
public string Account { get; set; }
public List<ChangeAddress> ChangeAddresses { get; set; }
}
}
......@@ -5,8 +5,12 @@ using Newtonsoft.Json.Linq;
namespace NBitcoin.RPC
{
class BlockExplorerFormatter : RawFormatter
internal class BlockExplorerFormatter : RawFormatter
{
internal BlockExplorerFormatter(Network network) : base(network)
{
}
protected override void BuildTransaction(JObject json, Transaction tx)
{
tx.Version = (uint)json.GetValue("ver");
......@@ -14,7 +18,7 @@ namespace NBitcoin.RPC
var vin = (JArray)json.GetValue("in");
int vinCount = (int)json.GetValue("vin_sz");
for(int i = 0; i < vinCount; i++)
for (int i = 0; i < vinCount; i++)
{
var jsonIn = (JObject)vin[i];
var txin = new TxIn();
......@@ -25,19 +29,19 @@ namespace NBitcoin.RPC
txin.PrevOut.N = (uint)prevout.GetValue("n");
var script = (string)jsonIn.GetValue("scriptSig");
if(script != null)
string script = (string)jsonIn.GetValue("scriptSig");
if (script != null)
{
txin.ScriptSig = new Script(script);
}
else
{
var coinbase = (string)jsonIn.GetValue("coinbase");
string coinbase = (string)jsonIn.GetValue("coinbase");
txin.ScriptSig = new Script(Encoders.Hex.DecodeData(coinbase));
}
var seq = jsonIn.GetValue("sequence");
if(seq != null)
JToken seq = jsonIn.GetValue("sequence");
if (seq != null)
{
txin.Sequence = (uint)seq;
}
......@@ -45,10 +49,10 @@ namespace NBitcoin.RPC
var vout = (JArray)json.GetValue("out");
int voutCount = (int)json.GetValue("vout_sz");
for(int i = 0; i < voutCount; i++)
for (int i = 0; i < voutCount; i++)
{
var jsonOut = (JObject)vout[i];
var txout = new NBitcoin.TxOut();
var txout = new TxOut();
tx.Outputs.Add(txout);
txout.Value = Money.Parse((string)jsonOut.GetValue("value"));
......@@ -70,9 +74,9 @@ namespace NBitcoin.RPC
writer.WritePropertyName("in");
writer.WriteStartArray();
foreach(var input in tx.Inputs.AsIndexedInputs())
foreach (IndexedTxIn input in tx.Inputs.AsIndexedInputs())
{
var txin = input.TxIn;
TxIn txin = input.TxIn;
writer.WriteStartObject();
writer.WritePropertyName("prev_out");
writer.WriteStartObject();
......@@ -80,7 +84,7 @@ namespace NBitcoin.RPC
WritePropertyValue(writer, "n", txin.PrevOut.N);
writer.WriteEndObject();
if(txin.PrevOut.Hash == uint256.Zero)
if (txin.PrevOut.Hash == uint256.Zero)
{
WritePropertyValue(writer, "coinbase", Encoders.Hex.EncodeData(txin.ScriptSig.ToBytes()));
}
......@@ -88,11 +92,11 @@ namespace NBitcoin.RPC
{
WritePropertyValue(writer, "scriptSig", txin.ScriptSig.ToString());
}
if(input.WitScript != WitScript.Empty)
if (input.WitScript != WitScript.Empty)
{
WritePropertyValue(writer, "witness", input.WitScript.ToString());
}
if(txin.Sequence != uint.MaxValue)
if (txin.Sequence != uint.MaxValue)
{
WritePropertyValue(writer, "sequence", (uint)txin.Sequence);
}
......@@ -102,7 +106,7 @@ namespace NBitcoin.RPC
writer.WritePropertyName("out");
writer.WriteStartArray();
foreach(var txout in tx.Outputs)
foreach (TxOut txout in tx.Outputs)
{
writer.WriteStartObject();
WritePropertyValue(writer, "value", txout.Value.ToString(false, false));
......
using System;
using System.Collections.Generic;
using System.Text;
namespace NBitcoin.RPC
{
public class ChangeAddress
{
public Money Amount { get; set; }
public BitcoinAddress Address { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace NBitcoin.RPC
{
public class RPCAccount
{
public Money Amount { get; set; }
public string AccountName { get; set; }
}
}
......@@ -8,31 +8,6 @@ using Newtonsoft.Json.Linq;
namespace NBitcoin.RPC
{
public class RPCAccount
{
public Money Amount { get; set; }
public string AccountName { get; set; }
}
public class ChangeAddress
{
public Money Amount { get; set; }
public BitcoinAddress Address { get; set; }
}
public class AddressGrouping
{
public AddressGrouping()
{
this.ChangeAddresses = new List<ChangeAddress>();
}
public BitcoinAddress PublicAddress { get; set; }
public Money Amount { get; set; }
public string Account { get; set; }
public List<ChangeAddress> ChangeAddresses { get; set; }
}
/*
Category Name Implemented
------------------ --------------------------- -----------------------
......@@ -214,8 +189,8 @@ namespace NBitcoin.RPC
if (options.SubtractFeeFromOutputs != null)
{
JArray array = new JArray();
foreach(var v in options.SubtractFeeFromOutputs)
var array = new JArray();
foreach (int v in options.SubtractFeeFromOutputs)
{
array.Add(new JValue(v));
}
......@@ -232,7 +207,7 @@ namespace NBitcoin.RPC
var r = (JObject)response.Result;
return new FundRawTransactionResponse()
{
Transaction = new Transaction(r["hex"].Value<string>()),
Transaction = this.network.CreateTransaction(r["hex"].Value<string>()),
Fee = Money.Coins(r["fee"].Value<decimal>()),
ChangePos = r["changepos"].Value<int>()
};
......@@ -246,7 +221,7 @@ namespace NBitcoin.RPC
return tx.ToHex();
// if there is, do this ACK so that NBitcoin does not change the version number
return Encoders.Hex.EncodeData(tx.ToBytes(NBitcoin.Protocol.ProtocolVersion.WITNESS_VERSION - 1));
return Encoders.Hex.EncodeData(tx.ToBytes(version: NBitcoin.Protocol.ProtocolVersion.WITNESS_VERSION - 1));
}
// getreceivedbyaddress
......@@ -609,7 +584,7 @@ namespace NBitcoin.RPC
public async Task<Transaction> SignRawTransactionAsync(Transaction tx)
{
RPCResponse result = await SendCommandAsync(RPCOperations.signrawtransaction, tx.ToHex()).ConfigureAwait(false);
return new Transaction(result.Result["hex"].Value<string>());
return this.network.CreateTransaction(result.Result["hex"].Value<string>());
}
}
}
......
......@@ -6,13 +6,13 @@ using Newtonsoft.Json.Linq;
namespace NBitcoin.RPC
{
abstract class RawFormatter
internal abstract class RawFormatter
{
public Network Network { get; set; }
protected RawFormatter()
protected RawFormatter(Network network)
{
this.Network = Network.Main;
this.Network = network;
}
protected abstract void BuildTransaction(JObject json, Transaction tx);
......@@ -34,7 +34,7 @@ namespace NBitcoin.RPC
public Transaction Parse(JObject obj)
{
Transaction tx = new Transaction();
var tx = new Transaction();
BuildTransaction(obj, tx);
return tx;
}
......
......@@ -27,44 +27,17 @@ namespace NBitcoin.RPC
private readonly Uri address;
private readonly Network network;
/// <summary>
/// Gets the <see cref="Network"/> instance for the client.
/// </summary>
public Network Network
{
get
{
return network;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="RestClient"/> class.
/// </summary>
/// <param name="address">The rest API endpoint</param>
/// <exception cref="System.ArgumentNullException">Null rest API endpoint</exception>
/// <exception cref="System.ArgumentException">Invalid value for RestResponseFormat</exception>
public RestClient(Uri address)
: this(address, Network.Main)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RestClient"/> class.
/// </summary>
/// <param name="address">The rest API endpoint</param>
/// <param name="network">The network to operate with</param>
/// <exception cref="System.ArgumentNullException">Null rest API endpoint</exception>
/// <exception cref="System.ArgumentException">Invalid value for RestResponseFormat</exception>
/// <exception cref="ArgumentNullException">Null rest API endpoint</exception>
/// <exception cref="ArgumentException">Invalid value for RestResponseFormat</exception>
public RestClient(Uri address, Network network)
{
if (address == null)
throw new ArgumentNullException("address");
if (network == null)
throw new ArgumentNullException("network");
this.address = address;
this.network = network;
this.address = address ?? throw new ArgumentNullException(nameof(address));
this.network = network ?? throw new ArgumentNullException(nameof(network));
}
/// <summary>
......@@ -72,14 +45,14 @@ namespace NBitcoin.RPC
/// </summary>
/// <param name="blockId">The block identifier.</param>
/// <returns>Given a block hash (id) returns the requested block object.</returns>
/// <exception cref="System.ArgumentNullException">blockId cannot be null.</exception>
/// <exception cref="ArgumentNullException">blockId cannot be null.</exception>
public async Task<Block> GetBlockAsync(uint256 blockId)
{
if (blockId == null)
throw new ArgumentNullException("blockId");
byte[] result = await SendRequestAsync("block", RestResponseFormat.Bin, blockId.ToString()).ConfigureAwait(false);
return new Block(result);
return Block.Load(result, this.network);
}
/// <summary>
......@@ -87,7 +60,7 @@ namespace NBitcoin.RPC
/// </summary>
/// <param name="blockId">The block identifier.</param>
/// <returns>Given a block hash (id) returns the requested block object.</returns>
/// <exception cref="System.ArgumentNullException">blockId cannot be null.</exception>
/// <exception cref="ArgumentNullException">blockId cannot be null.</exception>
public Block GetBlock(uint256 blockId)
{
return GetBlockAsync(blockId).GetAwaiter().GetResult();
......@@ -105,7 +78,7 @@ namespace NBitcoin.RPC
throw new ArgumentNullException("txId");
byte[] result = await SendRequestAsync("tx", RestResponseFormat.Bin, txId.ToString()).ConfigureAwait(false);
return new Transaction(result);
return this.network.CreateTransaction(result);
}
/// <summary>
......@@ -150,8 +123,8 @@ namespace NBitcoin.RPC
/// <param name="blockId">The initial block identifier.</param>
/// <param name="count">how many headers to get.</param>
/// <returns>Given a block hash (blockId) returns as much block headers as specified.</returns>
/// <exception cref="System.ArgumentNullException">blockId cannot be null</exception>
/// <exception cref="System.ArgumentOutOfRangeException">count must be greater or equal to one.</exception>
/// <exception cref="ArgumentNullException">blockId cannot be null</exception>
/// <exception cref="ArgumentOutOfRangeException">count must be greater or equal to one.</exception>
public IEnumerable<BlockHeader> GetBlockHeaders(uint256 blockId, int count)
{
return GetBlockHeadersAsync(blockId, count).GetAwaiter().GetResult();
......@@ -164,7 +137,7 @@ namespace NBitcoin.RPC
public async Task<ChainInfo> GetChainInfoAsync()
{
byte[] result = await SendRequestAsync("chaininfo", RestResponseFormat.Json).ConfigureAwait(false);
var o = JObject.Parse(Encoding.UTF8.GetString(result, 0, result.Length));
JObject o = JObject.Parse(Encoding.UTF8.GetString(result, 0, result.Length));
return new ChainInfo
{
......@@ -185,7 +158,7 @@ namespace NBitcoin.RPC
/// <param name="outPoints">The out points identifiers (TxIn-N).</param>
/// <param name="checkMempool">if set to <c>true</c> [check mempool].</param>
/// <returns>The unspent transaction outputs (UTXO) for the given outPoints.</returns>
/// <exception cref="System.ArgumentNullException">outPoints cannot be null.</exception>
/// <exception cref="ArgumentNullException">outPoints cannot be null.</exception>
public async Task<UTxOutputs> GetUnspentOutputsAsync(IEnumerable<OutPoint> outPoints, bool checkMempool)
{
if (outPoints == null)
......@@ -216,11 +189,11 @@ namespace NBitcoin.RPC
byte[] result = await SendRequestAsync($"gettxout/{txid.ToString()}/{vout.ToString() + (includeMemPool ? "/includemempool" : "")}",
RestResponseFormat.Json).ConfigureAwait(false);
var responseString = Encoding.UTF8.GetString(result, 0, result.Length);
string responseString = Encoding.UTF8.GetString(result, 0, result.Length);
if (string.IsNullOrEmpty(responseString))
return null;
var objectResult = JObject.Parse(responseString);
JObject objectResult = JObject.Parse(responseString);
return new UnspentTransaction(objectResult);
}
......@@ -232,23 +205,22 @@ namespace NBitcoin.RPC
using (WebResponse response = await GetWebResponseAsync(request).ConfigureAwait(false))
{
Stream stream = response.GetResponseStream();
var bytesToRead = (int)response.ContentLength;
int bytesToRead = (int)response.ContentLength;
byte[] buffer = await stream.ReadBytesAsync(bytesToRead).ConfigureAwait(false);
return buffer;
}
}
#region Private methods
private WebRequest BuildHttpRequest(string resource, RestResponseFormat format, params string[] parms)
{
var hasParams = parms != null && parms.Length > 0;
bool hasParams = parms != null && parms.Length > 0;
var uriBuilder = new UriBuilder(this.address);
uriBuilder.Path = "rest/" + resource + (hasParams ? "/" : "") + string.Join("/", parms) + "." + format.ToString().ToLowerInvariant();
HttpWebRequest request = WebRequest.CreateHttp(uriBuilder.Uri);
request.Method = "GET";
#if !(PORTABLE || NETCORE)
#if !NETCORE
request.KeepAlive = false;
#endif
return request;
......@@ -263,10 +235,8 @@ namespace NBitcoin.RPC
{
response = await request.GetResponseAsync().ConfigureAwait(false);
}
catch(WebException ex)
catch (WebException ex)
{
// "WebException status: {0}", ex.Status);
// Even if the request "failed" we need to continue reading the response from the router
response = ex.Response as HttpWebResponse;
......@@ -279,14 +249,13 @@ namespace NBitcoin.RPC
if (exception != null)
{
Stream stream = response.GetResponseStream();
var bytesToRead = (int)response.ContentLength;
int bytesToRead = (int)response.ContentLength;
byte[] buffer = await stream.ReadBytesAsync(bytesToRead).ConfigureAwait(false);
response.Dispose();
throw new RestApiException(Encoding.UTF8.GetString(buffer, 0, buffer.Length - 2), exception);
}
return response;
}
#endregion
}
public class RestApiException : Exception
......
......@@ -8,13 +8,10 @@ using Newtonsoft.Json.Linq;
namespace NBitcoin.RPC
{
class SatoshiFormatter : RawFormatter
internal class SatoshiFormatter : RawFormatter
{
private readonly Network network;
public SatoshiFormatter(Network network)
public SatoshiFormatter(Network network) : base(network)
{
this.network = network;
}
protected override void BuildTransaction(JObject json, Transaction tx)
......@@ -23,14 +20,14 @@ namespace NBitcoin.RPC
tx.LockTime = (uint)json.GetValue("locktime");
var vin = (JArray)json.GetValue("vin");
for(int i = 0; i < vin.Count; i++)
for (int i = 0; i < vin.Count; i++)
{
var jsonIn = (JObject)vin[i];
var txin = new TxIn();
tx.Inputs.Add(txin);
var script = (JObject)jsonIn.GetValue("scriptSig");
if(script != null)
if (script != null)
{
txin.ScriptSig = new Script(Encoders.Hex.DecodeData((string)script.GetValue("hex")));
txin.PrevOut.Hash = uint256.Parse((string)jsonIn.GetValue("txid"));
......@@ -38,7 +35,7 @@ namespace NBitcoin.RPC
}
else
{
var coinbase = (string)jsonIn.GetValue("coinbase");
string coinbase = (string)jsonIn.GetValue("coinbase");
txin.ScriptSig = new Script(Encoders.Hex.DecodeData(coinbase));
}
......@@ -47,14 +44,14 @@ namespace NBitcoin.RPC
}
var vout = (JArray)json.GetValue("vout");
for(int i = 0; i < vout.Count; i++)
for (int i = 0; i < vout.Count; i++)
{
var jsonOut = (JObject)vout[i];
var txout = new TxOut();
tx.Outputs.Add(txout);
var btc = (decimal)jsonOut.GetValue("value");
var satoshis = btc * Money.COIN;
decimal btc = (decimal)jsonOut.GetValue("value");
decimal satoshis = btc * Money.COIN;
txout.Value = new Money((long)(satoshis));
var script = (JObject)jsonOut.GetValue("scriptPubKey");
......@@ -70,11 +67,11 @@ namespace NBitcoin.RPC
writer.WritePropertyName("vin");
writer.WriteStartArray();
foreach(var txin in tx.Inputs)
foreach (TxIn txin in tx.Inputs)
{
writer.WriteStartObject();
if(txin.PrevOut.Hash == uint256.Zero)
if (txin.PrevOut.Hash == uint256.Zero)
{
WritePropertyValue(writer, "coinbase", Encoders.Hex.EncodeData(txin.ScriptSig.ToBytes()));
}
......@@ -99,7 +96,7 @@ namespace NBitcoin.RPC
writer.WriteStartArray();
int i = 0;
foreach(var txout in tx.Outputs)
foreach (TxOut txout in tx.Outputs)
{
writer.WriteStartObject();
writer.WritePropertyName("value");
......@@ -112,28 +109,28 @@ namespace NBitcoin.RPC
WritePropertyValue(writer, "asm", txout.ScriptPubKey.ToString());
WritePropertyValue(writer, "hex", Encoders.Hex.EncodeData(txout.ScriptPubKey.ToBytes()));
var destinations = new List<TxDestination>() { txout.ScriptPubKey.GetDestination(this.network) };
if(destinations[0] == null)
var destinations = new List<TxDestination>() { txout.ScriptPubKey.GetDestination(this.Network) };
if (destinations[0] == null)
{
destinations = txout.ScriptPubKey.GetDestinationPublicKeys(this.network)
destinations = txout.ScriptPubKey.GetDestinationPublicKeys(this.Network)
.Select(p => p.Hash)
.ToList<TxDestination>();
}
if(destinations.Count == 1)
if (destinations.Count == 1)
{
WritePropertyValue(writer, "reqSigs", 1);
WritePropertyValue(writer, "type", GetScriptType(txout.ScriptPubKey.FindTemplate(this.network)));
WritePropertyValue(writer, "type", GetScriptType(txout.ScriptPubKey.FindTemplate(this.Network)));
writer.WritePropertyName("addresses");
writer.WriteStartArray();
writer.WriteValue(destinations[0].GetAddress(Network).ToString());
writer.WriteValue(destinations[0].GetAddress(this.Network).ToString());
writer.WriteEndArray();
}
else
{
var multi = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(this.network, txout.ScriptPubKey);
PayToMultiSigTemplateParameters multi = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(txout.ScriptPubKey);
if (multi != null)
WritePropertyValue(writer, "reqSigs", multi.SignatureCount);
WritePropertyValue(writer, "type", GetScriptType(txout.ScriptPubKey.FindTemplate(this.network)));
WritePropertyValue(writer, "type", GetScriptType(txout.ScriptPubKey.FindTemplate(this.Network)));
if (multi != null)
{
writer.WritePropertyName("addresses");
......@@ -155,20 +152,20 @@ namespace NBitcoin.RPC
private string ValueFromAmount(Money money)
{
var satoshis = (decimal)money.Satoshi;
var btc = satoshis / Money.COIN;
decimal satoshis = (decimal)money.Satoshi;
decimal btc = satoshis / Money.COIN;
//return btc.ToString("0.###E+00", CultureInfo.InvariantCulture);
var result = ((double)btc).ToString(CultureInfo.InvariantCulture);
if(!result.ToCharArray().Contains('.'))
string result = ((double)btc).ToString(CultureInfo.InvariantCulture);
if (!result.ToCharArray().Contains('.'))
result = result + ".0";
return result;
}
private string GetScriptType(ScriptTemplate template)
{
if(template == null)
if (template == null)
return "nonstandard";
switch(template.Type)
switch (template.Type)
{
case TxOutType.TX_PUBKEY:
return "pubkey";
......
......@@ -326,7 +326,7 @@ namespace NBitcoin
{
public ScriptSigs()
{
WitSig = WitScript.Empty;
this.WitSig = WitScript.Empty;
}
public Script ScriptSig
{
......@@ -342,7 +342,7 @@ namespace NBitcoin
public class Script
{
static readonly Script _Empty = new Script();
private static readonly Script _Empty = new Script();
public static Script Empty
{
get
......@@ -363,23 +363,24 @@ namespace NBitcoin
public Script(IEnumerable<Op> ops)
{
MemoryStream ms = new MemoryStream();
foreach(var op in ops)
var ms = new MemoryStream();
foreach(Op op in ops)
{
op.WriteTo(ms);
}
_Script = ms.ToArray();
this._Script = ms.ToArray();
}
public Script(string script)
{
_Script = Parse(script);
this._Script = Parse(script);
}
private static byte[] Parse(string script)
{
var reader = new StringReader(script.Trim());
MemoryStream result = new MemoryStream();
var result = new MemoryStream();
while(reader.Peek() != -1)
{
Op.Read(reader).WriteTo(result);
......@@ -397,26 +398,25 @@ namespace NBitcoin
{
}
private Script(byte[] data, bool @unsafe, bool unused)
{
_Script = @unsafe ? data : data.ToArray();
this._Script = @unsafe ? data : data.ToArray();
}
public Script(IEnumerable<byte> data)
{
_Script = data.ToArray();
this._Script = data.ToArray();
}
public Script(byte[] data, bool compressed)
{
if(!compressed)
_Script = data.ToArray();
this._Script = data.ToArray();
else
{
ScriptCompressor compressor = new ScriptCompressor();
var compressor = new ScriptCompressor();
compressor.ReadWrite(data);
_Script = compressor.GetScript()._Script;
this._Script = compressor.GetScript()._Script;
}
}
......@@ -424,7 +424,7 @@ namespace NBitcoin
{
get
{
return _Script.Length;
return this._Script.Length;
}
}
......@@ -439,9 +439,9 @@ namespace NBitcoin
return this;
if(codeSeparatorIndex < -1)
throw new ArgumentOutOfRangeException("codeSeparatorIndex");
var separatorIndex = -1;
List<Op> ops = new List<Op>();
foreach(var op in ToOps())
int separatorIndex = -1;
var ops = new List<Op>();
foreach(Op op in ToOps())
{
if(op.Code == OpcodeType.OP_CODESEPARATOR)
separatorIndex++;
......@@ -456,7 +456,7 @@ namespace NBitcoin
public ScriptReader CreateReader()
{
return new ScriptReader(_Script);
return new ScriptReader(this._Script);
}
......@@ -476,7 +476,7 @@ namespace NBitcoin
{
if(pushedData.Length == 0)
return 0;
var standardOp = Op.GetPushOp(pushedData);
Op standardOp = Op.GetPushOp(pushedData);
return FindAndDelete(op =>
op.Code == standardOp.Code &&
op.PushData != null && Utils.ArrayEqual(op.PushData, pushedData));
......@@ -484,10 +484,10 @@ namespace NBitcoin
internal int FindAndDelete(Func<Op, bool> predicate)
{
int nFound = 0;
List<Op> operations = new List<Op>();
foreach(var op in ToOps())
var operations = new List<Op>();
foreach(Op op in ToOps())
{
var shouldDelete = predicate(op);
bool shouldDelete = predicate(op);
if(!shouldDelete)
{
operations.Add(op);
......@@ -497,16 +497,16 @@ namespace NBitcoin
}
if(nFound == 0)
return 0;
_Script = new Script(operations)._Script;
this._Script = new Script(operations)._Script;
return nFound;
}
public string ToHex()
{
return Encoders.Hex.EncodeData(_Script);
return Encoders.Hex.EncodeData(this._Script);
}
Script _PaymentScript;
private Script _PaymentScript;
/// <summary>
/// Get the P2SH scriptPubKey of this script
......@@ -515,7 +515,7 @@ namespace NBitcoin
{
get
{
return _PaymentScript ?? (_PaymentScript = PayToScriptHashTemplate.Instance.GenerateScriptPubKey(Hash));
return this._PaymentScript ?? (this._PaymentScript = PayToScriptHashTemplate.Instance.GenerateScriptPubKey(this.Hash));
}
}
......@@ -525,7 +525,7 @@ namespace NBitcoin
/// </summary>
public bool IsWitness(Network network)
{
return PayToWitTemplate.Instance.CheckScriptPubKey(network, this);
return PayToWitTemplate.Instance.CheckScriptPubKey(this);
}
public override string ToString()
......@@ -533,7 +533,7 @@ namespace NBitcoin
// by default StringBuilder capacity is 16 (too small)
// 300 is enough for P2PKH
var builder = new StringBuilder(300);
using (var reader = new ScriptReader(_Script))
using (var reader = new ScriptReader(this._Script))
{
Op op;
while ((op = reader.Read()) != null)
......@@ -552,7 +552,7 @@ namespace NBitcoin
{
using (ScriptReader reader = CreateReader())
{
foreach (var script in reader.ToEnumerable())
foreach (Op script in reader.ToEnumerable())
{
if (script.PushData == null)
return false;
......@@ -595,7 +595,7 @@ namespace NBitcoin
//https://en.bitcoin.it/wiki/OP_CHECKSIG
public static uint256 SignatureHash(Network network, ICoin coin, Transaction txTo, SigHash nHashType = SigHash.All)
{
var input = txTo.Inputs.AsIndexedInputs().FirstOrDefault(i => i.PrevOut == coin.Outpoint);
IndexedTxIn input = txTo.Inputs.AsIndexedInputs().FirstOrDefault(i => i.PrevOut == coin.Outpoint);
if(input == null)
throw new ArgumentException("coin should be spent spent in txTo", "coin");
return input.GetSignatureHash(network, coin, nHashType);
......@@ -664,9 +664,6 @@ namespace NBitcoin
return GetHash(sss);
}
if(nIn >= txTo.Inputs.Count)
{
Utils.log("ERROR: SignatureHash() : nIn=" + nIn + " out of range\n");
......@@ -688,10 +685,10 @@ namespace NBitcoin
var scriptCopy = new Script(scriptCode._Script);
scriptCopy.FindAndDelete(OpcodeType.OP_CODESEPARATOR);
var txCopy = Transaction.Load(txTo.ToBytes(), network);
Transaction txCopy = network.CreateTransaction(txTo.ToBytes());
//Set all TxIn script to empty string
foreach(var txin in txCopy.Inputs)
foreach(TxIn txin in txCopy.Inputs)
{
txin.ScriptSig = new Script();
}
......@@ -704,7 +701,7 @@ namespace NBitcoin
txCopy.Outputs.Clear();
//All other inputs aside from the current input in txCopy have their nSequence index set to zero
foreach(var input in txCopy.Inputs.Where((x, i) => i != nIn))
foreach(TxIn input in txCopy.Inputs.Where((x, i) => i != nIn))
input.Sequence = 0;
}
else if(hashType == SigHash.Single)
......@@ -712,14 +709,14 @@ namespace NBitcoin
//The output of txCopy is resized to the size of the current input index+1.
txCopy.Outputs.RemoveRange(nIn + 1, txCopy.Outputs.Count - (nIn + 1));
//All other txCopy outputs aside from the output that is the same as the current input index are set to a blank script and a value of (long) -1.
for(var i = 0; i < txCopy.Outputs.Count; i++)
for(int i = 0; i < txCopy.Outputs.Count; i++)
{
if(i == nIn)
continue;
txCopy.Outputs[i] = new TxOut();
}
//All other txCopy inputs aside from the current input are set to have an nSequence index of zero.
foreach(var input in txCopy.Inputs.Where((x, i) => i != nIn))
foreach(TxIn input in txCopy.Inputs.Where((x, i) => i != nIn))
input.Sequence = 0;
}
......@@ -727,7 +724,7 @@ namespace NBitcoin
if((nHashType & SigHash.AnyoneCanPay) != 0)
{
//The txCopy input vector is resized to a length of one.
var script = txCopy.Inputs[nIn];
TxIn script = txCopy.Inputs[nIn];
txCopy.Inputs.Clear();
txCopy.Inputs.Add(script);
//The subScript (lead in by its length as a var-integer encoded!) is set as the first and only member of this vector.
......@@ -736,7 +733,7 @@ namespace NBitcoin
//Serialize TxCopy, append 4 byte hashtypecode
var stream = CreateHashWriter(sigversion);
BitcoinStream stream = CreateHashWriter(sigversion);
txCopy.ReadWrite(stream);
stream.ReadWrite((uint)nHashType);
return GetHash(stream);
......@@ -744,7 +741,7 @@ namespace NBitcoin
private static uint256 GetHash(BitcoinStream stream)
{
var preimage = ((HashStream)stream.Inner).GetHash();
uint256 preimage = ((HashStream)stream.Inner).GetHash();
stream.Inner.Dispose();
return preimage;
}
......@@ -753,7 +750,7 @@ namespace NBitcoin
{
uint256 hashOutputs;
BitcoinStream ss = CreateHashWriter(HashVersion.Witness);
foreach(var txout in txTo.Outputs)
foreach(TxOut txout in txTo.Outputs)
{
ss.ReadWrite(txout);
}
......@@ -765,7 +762,7 @@ namespace NBitcoin
{
uint256 hashSequence;
BitcoinStream ss = CreateHashWriter(HashVersion.Witness);
foreach(var input in txTo.Inputs)
foreach(TxIn input in txTo.Inputs)
{
ss.ReadWrite((uint)input.Sequence);
}
......@@ -777,7 +774,7 @@ namespace NBitcoin
{
uint256 hashPrevouts;
BitcoinStream ss = CreateHashWriter(HashVersion.Witness);
foreach(var input in txTo.Inputs)
foreach(TxIn input in txTo.Inputs)
{
ss.ReadWrite(input.PrevOut);
}
......@@ -787,8 +784,8 @@ namespace NBitcoin
private static BitcoinStream CreateHashWriter(HashVersion version)
{
HashStream hs = new HashStream();
BitcoinStream stream = new BitcoinStream(hs, true);
var hs = new HashStream();
var stream = new BitcoinStream(hs, true);
stream.Type = SerializationType.Hash;
stream.TransactionOptions = version == HashVersion.Original ? TransactionOptions.None : TransactionOptions.Witness;
return stream;
......@@ -812,7 +809,7 @@ namespace NBitcoin
public IEnumerable<Op> ToOps()
{
using (ScriptReader reader = new ScriptReader(_Script))
using (var reader = new ScriptReader(this._Script))
{
return reader.ToEnumerable().ToList();
}
......@@ -822,7 +819,7 @@ namespace NBitcoin
{
uint n = 0;
Op lastOpcode = null;
foreach(var op in ToOps())
foreach(Op op in ToOps())
{
if(op.Code == OpcodeType.OP_CHECKSIG || op.Code == OpcodeType.OP_CHECKSIGVERIFY)
n++;
......@@ -838,53 +835,54 @@ namespace NBitcoin
return n;
}
ScriptId _Hash;
private ScriptId _Hash;
public ScriptId Hash
{
get
{
return _Hash ?? (_Hash = new ScriptId(this));
return this._Hash ?? (this._Hash = new ScriptId(this));
}
}
WitScriptId _WitHash;
private WitScriptId _WitHash;
public WitScriptId WitHash
{
get
{
return _WitHash ?? (_WitHash = new WitScriptId(this));
return this._WitHash ?? (this._WitHash = new WitScriptId(this));
}
}
public BitcoinScriptAddress GetScriptAddress(Network network)
{
return (BitcoinScriptAddress)Hash.GetAddress(network);
return (BitcoinScriptAddress) this.Hash.GetAddress(network);
}
public bool IsPayToScriptHash(Network network)
{
return PayToScriptHashTemplate.Instance.CheckScriptPubKey(network, this);
return PayToScriptHashTemplate.Instance.CheckScriptPubKey(this);
}
public BitcoinWitScriptAddress GetWitScriptAddress(Network network)
{
return (BitcoinWitScriptAddress)WitHash.GetAddress(network);
return (BitcoinWitScriptAddress) this.WitHash.GetAddress(network);
}
public uint GetSigOpCount(Network network, Script scriptSig)
{
if(!this.IsPayToScriptHash(network))
return this.GetSigOpCount(true);
if(!IsPayToScriptHash(network))
return GetSigOpCount(true);
// This is a pay-to-script-hash scriptPubKey;
// get the last item that the scriptSig
// pushes onto the stack:
var validSig = new PayToScriptHashTemplate().CheckScriptSig(network, scriptSig, this);
bool validSig = new PayToScriptHashTemplate().CheckScriptSig(network, scriptSig, this);
return !validSig ? 0 : new Script(scriptSig.ToOps().Last().PushData).GetSigOpCount(true);
// ... and return its opcount:
}
public ScriptTemplate FindTemplate(Network network)
{
return StandardScripts.GetTemplateFromScriptPubKey(network, this);
return StandardScripts.GetTemplateFromScriptPubKey(this);
}
/// <summary>
......@@ -894,7 +892,7 @@ namespace NBitcoin
/// <returns></returns>
public BitcoinAddress GetSignerAddress(Network network)
{
var sig = GetSigner(network);
TxDestination sig = GetSigner(network);
return sig == null ? null : sig.GetAddress(network);
}
......@@ -904,12 +902,12 @@ namespace NBitcoin
/// <returns>The network</returns>
public TxDestination GetSigner(Network network)
{
var pubKey = PayToPubkeyHashTemplate.Instance.ExtractScriptSigParameters(network, this);
PayToPubkeyHashScriptSigParameters pubKey = PayToPubkeyHashTemplate.Instance.ExtractScriptSigParameters(network, this);
if(pubKey != null)
{
return pubKey.PublicKey.Hash;
}
var p2sh = PayToScriptHashTemplate.Instance.ExtractScriptSigParameters(network, this);
PayToScriptHashSigParameters p2sh = PayToScriptHashTemplate.Instance.ExtractScriptSigParameters(network, this);
return p2sh != null ? p2sh.RedeemScript.Hash : null;
}
......@@ -920,7 +918,7 @@ namespace NBitcoin
/// <returns></returns>
public BitcoinAddress GetDestinationAddress(Network network)
{
var dest = GetDestination(network);
TxDestination dest = GetDestination(network);
return dest == null ? null : dest.GetAddress(network);
}
......@@ -931,13 +929,13 @@ namespace NBitcoin
/// <returns></returns>
public TxDestination GetDestination(Network network)
{
var pubKeyHashParams = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(this);
KeyId pubKeyHashParams = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(this);
if(pubKeyHashParams != null)
return pubKeyHashParams;
var scriptHashParams = PayToScriptHashTemplate.Instance.ExtractScriptPubKeyParameters(this);
ScriptId scriptHashParams = PayToScriptHashTemplate.Instance.ExtractScriptPubKeyParameters(this);
if(scriptHashParams != null)
return scriptHashParams;
var wit = PayToWitTemplate.Instance.ExtractScriptPubKeyParameters(network, this);
TxDestination wit = PayToWitTemplate.Instance.ExtractScriptPubKeyParameters(network, this);
return wit;
}
......@@ -948,15 +946,15 @@ namespace NBitcoin
/// <returns></returns>
public PubKey[] GetDestinationPublicKeys(Network network)
{
List<PubKey> result = new List<PubKey>();
var single = PayToPubkeyTemplate.Instance.ExtractScriptPubKeyParameters(this);
var result = new List<PubKey>();
PubKey single = PayToPubkeyTemplate.Instance.ExtractScriptPubKeyParameters(this);
if(single != null)
{
result.Add(single);
}
else
{
var multiSig = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(network, this);
PayToMultiSigTemplateParameters multiSig = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(this);
if(multiSig != null)
{
result.AddRange(multiSig.PubKeys);
......@@ -992,7 +990,7 @@ namespace NBitcoin
[Obsolete("Use ToBytes instead")]
public byte[] ToRawScript(bool @unsafe)
{
return @unsafe ? _Script : _Script.ToArray();
return @unsafe ? this._Script : this._Script.ToArray();
}
/// <summary>
......@@ -1002,7 +1000,7 @@ namespace NBitcoin
/// <returns></returns>
public byte[] ToBytes(bool @unsafe)
{
return @unsafe ? _Script : _Script.ToArray();
return @unsafe ? this._Script : this._Script.ToArray();
}
public byte[] ToCompressedBytes()
......@@ -1028,19 +1026,19 @@ namespace NBitcoin
public static bool VerifyScript(Network network, Script scriptPubKey, Transaction tx, int i, Money value, ScriptVerify scriptVerify = ScriptVerify.Standard, SigHash sigHash = SigHash.Undefined)
{
var scriptSig = tx.Inputs[i].ScriptSig;
Script scriptSig = tx.Inputs[i].ScriptSig;
return VerifyScript(network, scriptSig, scriptPubKey, tx, i, value, scriptVerify, sigHash, out ScriptError unused);
}
public static bool VerifyScript(Network network, Script scriptPubKey, Transaction tx, int i, Money value, out ScriptError error)
{
var scriptSig = tx.Inputs[i].ScriptSig;
Script scriptSig = tx.Inputs[i].ScriptSig;
return VerifyScript(network, scriptSig, scriptPubKey, tx, i, value, ScriptVerify.Standard, SigHash.Undefined, out error);
}
public static bool VerifyScript(Network network, Script scriptPubKey, Transaction tx, int i, Money value, ScriptVerify scriptVerify, SigHash sigHash, out ScriptError error)
{
var scriptSig = tx.Inputs[i].ScriptSig;
Script scriptSig = tx.Inputs[i].ScriptSig;
return VerifyScript(network, scriptSig, scriptPubKey, tx, i, value, scriptVerify, sigHash, out error);
}
......@@ -1051,13 +1049,11 @@ namespace NBitcoin
SigHash = sigHash,
ScriptVerify = scriptVerify
};
var result = eval.VerifyScript(scriptSig, scriptPubKey, tx, i, value);
bool result = eval.VerifyScript(scriptSig, scriptPubKey, tx, i, value);
error = eval.Error;
return result;
}
#if !NOCONSENSUSLIB
public const string LibConsensusDll = "libbitcoinconsensus-0.dll";
public enum BitcoinConsensusError
{
......@@ -1089,28 +1085,27 @@ namespace NBitcoin
public static bool VerifyScriptConsensus(Script scriptPubKey, Transaction tx, uint nIn, ScriptVerify flags, out BitcoinConsensusError err)
{
var scriptPubKeyBytes = scriptPubKey.ToBytes();
var txToBytes = tx.ToBytes();
byte[] scriptPubKeyBytes = scriptPubKey.ToBytes();
byte[] txToBytes = tx.ToBytes();
err = BitcoinConsensusError.ERR_OK;
var valid = VerifyScriptConsensus(scriptPubKeyBytes, (uint)scriptPubKeyBytes.Length, txToBytes, (uint)txToBytes.Length, nIn, flags, ref err);
int valid = VerifyScriptConsensus(scriptPubKeyBytes, (uint)scriptPubKeyBytes.Length, txToBytes, (uint)txToBytes.Length, nIn, flags, ref err);
return valid == 1;
}
public static bool VerifyScriptConsensus(Script scriptPubKey, Transaction tx, uint nIn, Money amount, ScriptVerify flags, out BitcoinConsensusError err)
{
var scriptPubKeyBytes = scriptPubKey.ToBytes();
var txToBytes = tx.ToBytes();
byte[] scriptPubKeyBytes = scriptPubKey.ToBytes();
byte[] txToBytes = tx.ToBytes();
err = BitcoinConsensusError.ERR_OK;
var valid = VerifyScriptConsensusWithAmount(scriptPubKeyBytes, (uint)scriptPubKeyBytes.Length, amount.Satoshi, txToBytes, (uint)txToBytes.Length, nIn, flags, ref err);
int valid = VerifyScriptConsensusWithAmount(scriptPubKeyBytes, (uint)scriptPubKeyBytes.Length, amount.Satoshi, txToBytes, (uint)txToBytes.Length, nIn, flags, ref err);
return valid == 1;
}
#endif
public bool IsUnspendable
{
get
{
return _Script.Length > 0 && _Script[0] == (byte)OpcodeType.OP_RETURN;
return this._Script.Length > 0 && this._Script[0] == (byte)OpcodeType.OP_RETURN;
}
}
......@@ -1121,8 +1116,8 @@ namespace NBitcoin
public override bool Equals(object obj)
{
Script item = obj as Script;
return item != null && Utils.ArrayEqual(item._Script, _Script);
var item = obj as Script;
return item != null && Utils.ArrayEqual(item._Script, this._Script);
}
public static bool operator ==(Script a, Script b)
{
......@@ -1140,12 +1135,12 @@ namespace NBitcoin
public override int GetHashCode()
{
return Utils.GetHashCode(_Script);
return Utils.GetHashCode(this._Script);
}
public Script Clone()
{
return new Script(_Script);
return new Script(this._Script);
}
public static Script CombineSignatures(Network network, Script scriptPubKey, Transaction transaction, int n, Script scriptSig1, Script scriptSig2)
......@@ -1163,10 +1158,10 @@ namespace NBitcoin
if(scriptPubKey == null)
scriptPubKey = new Script();
var scriptSig1 = input1.ScriptSig;
var scriptSig2 = input2.ScriptSig;
HashVersion hashVersion = HashVersion.Original;
var isWitness = input1.WitSig != WitScript.Empty || input2.WitSig != WitScript.Empty;
Script scriptSig1 = input1.ScriptSig;
Script scriptSig2 = input2.ScriptSig;
var hashVersion = HashVersion.Original;
bool isWitness = input1.WitSig != WitScript.Empty || input2.WitSig != WitScript.Empty;
if(isWitness)
{
scriptSig1 = input1.WitSig.ToScript();
......@@ -1178,21 +1173,23 @@ namespace NBitcoin
context.ScriptVerify = ScriptVerify.StrictEnc;
context.EvalScript(scriptSig1, checker, hashVersion);
var stack1 = context.Stack.AsInternalArray();
byte[][] stack1 = context.Stack.AsInternalArray();
context = new ScriptEvaluationContext(network);
context.ScriptVerify = ScriptVerify.StrictEnc;
context.EvalScript(scriptSig2, checker, hashVersion);
var stack2 = context.Stack.AsInternalArray();
var result = CombineSignatures(network, scriptPubKey, checker, stack1, stack2, hashVersion);
byte[][] stack2 = context.Stack.AsInternalArray();
Script result = CombineSignatures(network, scriptPubKey, checker, stack1, stack2, hashVersion);
if(result == null)
return scriptSig1.Length < scriptSig2.Length ? input2 : input1;
if(!isWitness)
{
return new ScriptSigs()
{
ScriptSig = result,
WitSig = WitScript.Empty
};
}
else
{
return new ScriptSigs()
......@@ -1205,21 +1202,24 @@ namespace NBitcoin
private static Script CombineSignatures(Network network, Script scriptPubKey, TransactionChecker checker, byte[][] sigs1, byte[][] sigs2, HashVersion hashVersion)
{
var template = StandardScripts.GetTemplateFromScriptPubKey(network, scriptPubKey);
ScriptTemplate template = StandardScripts.GetTemplateFromScriptPubKey(scriptPubKey);
if(template is PayToWitPubKeyHashTemplate)
{
scriptPubKey = new KeyId(scriptPubKey.ToBytes(true).SafeSubarray(1, 20)).ScriptPubKey;
template = StandardScripts.GetTemplateFromScriptPubKey(network, scriptPubKey);
template = StandardScripts.GetTemplateFromScriptPubKey(scriptPubKey);
}
if(template == null || template is TxNullDataTemplate)
return PushAll(Max(sigs1, sigs2));
if(template is PayToPubkeyTemplate || template is PayToPubkeyHashTemplate)
{
if(sigs1.Length == 0 || sigs1[0].Length == 0)
return PushAll(sigs2);
else
return PushAll(sigs1);
}
if(template is PayToScriptHashTemplate || template is PayToWitTemplate)
{
if(sigs1.Length == 0 || sigs1[sigs1.Length - 1].Length == 0)
......@@ -1228,7 +1228,7 @@ namespace NBitcoin
if(sigs2.Length == 0 || sigs2[sigs2.Length - 1].Length == 0)
return PushAll(sigs1);
var redeemBytes = sigs1[sigs1.Length - 1];
byte[] redeemBytes = sigs1[sigs1.Length - 1];
var redeem = new Script(redeemBytes);
sigs1 = sigs1.Take(sigs1.Length - 1).ToArray();
sigs2 = sigs2.Take(sigs2.Length - 1).ToArray();
......@@ -1248,8 +1248,8 @@ namespace NBitcoin
private static Script CombineMultisig(Network network, Script scriptPubKey, TransactionChecker checker, byte[][] sigs1, byte[][] sigs2, HashVersion hashVersion)
{
// Combine all the signatures we've got:
List<TransactionSignature> allsigs = new List<TransactionSignature>();
foreach(var v in sigs1)
var allsigs = new List<TransactionSignature>();
foreach(byte[] v in sigs1)
{
if(TransactionSignature.IsValid(network, v))
{
......@@ -1258,7 +1258,7 @@ namespace NBitcoin
}
foreach(var v in sigs2)
foreach(byte[] v in sigs2)
{
if(TransactionSignature.IsValid(network, v))
{
......@@ -1266,20 +1266,20 @@ namespace NBitcoin
}
}
var multiSigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(network, scriptPubKey);
PayToMultiSigTemplateParameters multiSigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);
if(multiSigParams == null)
throw new InvalidOperationException("The scriptPubKey is not a valid multi sig");
Dictionary<PubKey, TransactionSignature> sigs = new Dictionary<PubKey, TransactionSignature>();
var sigs = new Dictionary<PubKey, TransactionSignature>();
foreach(var sig in allsigs)
foreach(TransactionSignature sig in allsigs)
{
foreach(var pubkey in multiSigParams.PubKeys)
foreach(PubKey pubkey in multiSigParams.PubKeys)
{
if(sigs.ContainsKey(pubkey))
continue; // Already got a sig for this pubkey
ScriptEvaluationContext eval = new ScriptEvaluationContext(network);
var eval = new ScriptEvaluationContext(network);
if(eval.CheckSig(sig, pubkey, scriptPubKey, checker, hashVersion))
{
sigs.AddOrReplace(pubkey, sig);
......@@ -1290,8 +1290,8 @@ namespace NBitcoin
// Now build a merged CScript:
int nSigsHave = 0;
Script result = new Script(OpcodeType.OP_0); // pop-one-too-many workaround
foreach(var pubkey in multiSigParams.PubKeys)
var result = new Script(OpcodeType.OP_0); // pop-one-too-many workaround
foreach(PubKey pubkey in multiSigParams.PubKeys)
{
if(sigs.ContainsKey(pubkey))
{
......@@ -1311,8 +1311,8 @@ namespace NBitcoin
private static Script PushAll(byte[][] stack)
{
Script s = new Script();
foreach(var push in stack)
var s = new Script();
foreach(byte[] push in stack)
{
s += Op.GetPushOp(push);
}
......
......@@ -4,10 +4,9 @@ using NBitcoin.Policy;
namespace NBitcoin
{
public static class StandardScripts
{
static readonly ScriptTemplate[] _StandardTemplates = new ScriptTemplate[]
private static readonly ScriptTemplate[] _StandardTemplates = new ScriptTemplate[]
{
PayToPubkeyHashTemplate.Instance,
PayToPubkeyTemplate.Instance,
......@@ -17,10 +16,8 @@ namespace NBitcoin
PayToWitTemplate.Instance
};
public static bool IsStandardTransaction(Transaction tx, Network network = null)
public static bool IsStandardTransaction(Transaction tx, Network network)
{
network = network ?? Network.Main;
return new StandardTransactionPolicy(network).Check(tx, null).Length == 0;
}
......@@ -29,25 +26,25 @@ namespace NBitcoin
return tx.Outputs.All(vout => IsStandardScriptPubKey(network, vout.ScriptPubKey));
}
public static ScriptTemplate GetTemplateFromScriptPubKey(Network network, Script script)
public static ScriptTemplate GetTemplateFromScriptPubKey(Script script)
{
return _StandardTemplates.FirstOrDefault(t => t.CheckScriptPubKey(network, script));
return _StandardTemplates.FirstOrDefault(t => t.CheckScriptPubKey(script));
}
public static bool IsStandardScriptPubKey(Network network, Script scriptPubKey)
{
return _StandardTemplates.Any(template => template.CheckScriptPubKey(network, scriptPubKey));
return _StandardTemplates.Any(template => template.CheckScriptPubKey(scriptPubKey));
}
private static bool IsStandardScriptSig(Network network, Script scriptSig, Script scriptPubKey)
{
var template = GetTemplateFromScriptPubKey(network, scriptPubKey);
ScriptTemplate template = GetTemplateFromScriptPubKey(scriptPubKey);
if(template == null)
return false;
return template.CheckScriptSig(network, scriptSig, scriptPubKey);
}
//
// Check transaction inputs, and make sure any
// pay-to-script-hash transactions are evaluating IsStandard scripts
//
......@@ -57,13 +54,12 @@ namespace NBitcoin
// script can be anything; an attacker could use a very
// expensive-to-check-upon-redemption script like:
// DUP CHECKSIG DROP ... repeated 100 times... OP_1
//
public static bool AreInputsStandard(Network network, Transaction tx, CoinsView coinsView)
{
if(tx.IsCoinBase)
return true; // Coinbases don't use vin normally
foreach(var input in tx.Inputs)
foreach(TxIn input in tx.Inputs)
{
TxOut prev = coinsView.GetOutputFor(input);
if(prev == null)
......
......@@ -16,9 +16,10 @@ namespace NBitcoin.Stealth
}
throw new ArgumentException("No nonce can satisfy the given bitfield, use another ephemKey");
}
public static StealthMetadata TryParse(Script metadata)
{
StealthMetadata result = new StealthMetadata();
var result = new StealthMetadata();
try
{
if(!Fill(result, metadata))
......@@ -30,9 +31,11 @@ namespace NBitcoin.Stealth
}
return result;
}
private StealthMetadata()
{
}
public StealthMetadata(Script metadata)
{
if(!Fill(this, metadata))
......@@ -43,19 +46,20 @@ namespace NBitcoin.Stealth
{
var data = new MemoryStream();
data.WriteByte(6);
var b = Utils.ToBytes(nonce, true);
byte[] b = Utils.ToBytes(nonce, true);
data.Write(b, 0, b.Length);
data.Write(ephemKey.PubKey.Compress().ToBytes(), 0, 33);
Fill(this, new Script(OpcodeType.OP_RETURN, Op.GetPushOp(data.ToArray())));
}
static TxNullDataTemplate _Template = new TxNullDataTemplate(1024 * 4);
private static TxNullDataTemplate _Template = new TxNullDataTemplate(1024 * 4);
private static bool Fill(StealthMetadata output, Script metadata)
{
var datas = _Template.ExtractScriptPubKeyParameters(Network.Main, metadata);
byte[][] datas = _Template.ExtractScriptPubKeyParameters(metadata);
if(datas == null)
return false;
foreach(var data in datas)
foreach(byte[] data in datas)
{
if(Fill(output, metadata, data))
return true;
......@@ -67,7 +71,7 @@ namespace NBitcoin.Stealth
{
if(data == null || data.Length != 1 + 4 + 33)
return false;
MemoryStream ms = new MemoryStream(data);
var ms = new MemoryStream(data);
output.Version = ms.ReadByte();
if(output.Version != 6)
return false;
......
......@@ -11,7 +11,7 @@ namespace NBitcoin.Stealth
{
get
{
return _Payment;
return this._Payment;
}
}
private readonly KeyId _ID;
......@@ -19,18 +19,18 @@ namespace NBitcoin.Stealth
{
get
{
return _ID;
return this._ID;
}
}
public StealthSpendKey(KeyId id, StealthPayment payment)
{
_ID = id;
_Payment = payment;
this._ID = id;
this._Payment = payment;
}
public BitcoinAddress GetAddress(Network network)
{
return new BitcoinPubKeyAddress(ID, network);
return new BitcoinPubKeyAddress(this.ID, network);
}
}
......@@ -38,13 +38,13 @@ namespace NBitcoin.Stealth
{
public StealthPayment(BitcoinStealthAddress address, Key ephemKey, StealthMetadata metadata)
{
Metadata = metadata;
ScriptPubKey = CreatePaymentScript(address.SignatureCount, address.SpendPubKeys, ephemKey, address.ScanPubKey);
this.Metadata = metadata;
this.ScriptPubKey = CreatePaymentScript(address.SignatureCount, address.SpendPubKeys, ephemKey, address.ScanPubKey);
if(address.SignatureCount > 1)
{
Redeem = ScriptPubKey;
ScriptPubKey = ScriptPubKey.Hash.ScriptPubKey;
this.Redeem = this.ScriptPubKey;
this.ScriptPubKey = this.ScriptPubKey.Hash.ScriptPubKey;
}
SetStealthKeys();
}
......@@ -71,17 +71,16 @@ namespace NBitcoin.Stealth
return CreatePaymentScript(address.SignatureCount, address.SpendPubKeys.Select(p => p.UncoverReceiver(scan, ephemKey)).ToArray());
}
public static KeyId[] ExtractKeyIDs(Script script)
{
var keyId = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(script);
KeyId keyId = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(script);
if(keyId != null)
{
return new[] { keyId };
}
else
{
var para = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(Network.Main, script);
PayToMultiSigTemplateParameters para = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(script);
if(para == null)
throw new ArgumentException("Invalid stealth spendable output script", "spendable");
return para.PubKeys.Select(k => k.Hash).ToArray();
......@@ -93,22 +92,23 @@ namespace NBitcoin.Stealth
get;
private set;
}
public BitcoinAddress[] GetAddresses(Network network)
{
return StealthKeys.Select(k => k.GetAddress(network)).ToArray();
return this.StealthKeys.Select(k => k.GetAddress(network)).ToArray();
}
public StealthPayment(Script scriptPubKey, Script redeem, StealthMetadata metadata)
{
Metadata = metadata;
ScriptPubKey = scriptPubKey;
Redeem = redeem;
this.Metadata = metadata;
this.ScriptPubKey = scriptPubKey;
this.Redeem = redeem;
SetStealthKeys();
}
private void SetStealthKeys()
{
StealthKeys = ExtractKeyIDs(Redeem ?? ScriptPubKey).Select(id => new StealthSpendKey(id, this)).ToArray();
this.StealthKeys = ExtractKeyIDs(this.Redeem ?? this.ScriptPubKey).Select(id => new StealthSpendKey(id, this)).ToArray();
}
......@@ -134,20 +134,20 @@ namespace NBitcoin.Stealth
throw new ArgumentNullException("transaction");
if(value == null)
throw new ArgumentNullException("value");
transaction.Outputs.Add(new TxOut(0, Metadata.Script));
transaction.Outputs.Add(new TxOut(value, ScriptPubKey));
transaction.Outputs.Add(new TxOut(0, this.Metadata.Script));
transaction.Outputs.Add(new TxOut(value, this.ScriptPubKey));
}
public static StealthPayment[] GetPayments(Transaction transaction, BitcoinStealthAddress address, Key scan)
{
List<StealthPayment> result = new List<StealthPayment>();
var result = new List<StealthPayment>();
for(int i = 0; i < transaction.Outputs.Count - 1; i++)
{
var metadata = StealthMetadata.TryParse(transaction.Outputs[i].ScriptPubKey);
StealthMetadata metadata = StealthMetadata.TryParse(transaction.Outputs[i].ScriptPubKey);
if(metadata != null && (address == null || address.Prefix.Match(metadata.BitField)))
{
var scriptPubKey = transaction.Outputs[i + 1].ScriptPubKey;
var scriptId = PayToScriptHashTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);
Script scriptPubKey = transaction.Outputs[i + 1].ScriptPubKey;
ScriptId scriptId = PayToScriptHashTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);
Script expectedScriptPubKey = address == null ? scriptPubKey : null;
Script redeem = null;
......
......@@ -33,47 +33,64 @@ namespace NBitcoin
{
}
Random _Rand = new Random();
private Random _Rand = new Random();
public DefaultCoinSelector(int seed)
{
_Rand = new Random(seed);
this._Rand = new Random(seed);
}
/// <summary>
/// Select all coins belonging to same scriptPubKey together to protect privacy. (Default: true)
/// </summary>
public bool GroupByScriptPubKey
{
get; set;
} = true;
#region ICoinSelector Members
public IEnumerable<ICoin> Select(IEnumerable<ICoin> coins, IMoney target)
{
var zero = target.Sub(target);
var targetCoin = coins
.FirstOrDefault(c => c.Amount.CompareTo(target) == 0);
//If any of your UTXO² matches the Target¹ it will be used.
if(targetCoin != null)
return new[] { targetCoin };
IMoney zero = target.Sub(target);
List<ICoin> result = new List<ICoin>();
var result = new List<ICoin>();
IMoney total = zero;
if(target.CompareTo(zero) == 0)
if (target.CompareTo(zero) == 0)
return result;
var orderedCoins = coins.OrderBy(s => s.Amount).ToArray();
var orderedCoinGroups = coins.GroupBy(c => this.GroupByScriptPubKey ? c.TxOut.ScriptPubKey : new Key().ScriptPubKey)
.Select(scriptPubKeyCoins => new
{
Amount = scriptPubKeyCoins.Select(c => c.Amount).Sum(zero),
Coins = scriptPubKeyCoins.ToList()
}).OrderBy(c => c.Amount);
foreach(var coin in orderedCoins)
var targetCoin = orderedCoinGroups
.FirstOrDefault(c => c.Amount.CompareTo(target) == 0);
//If any of your UTXO² matches the Target¹ it will be used.
if (targetCoin != null)
return targetCoin.Coins;
foreach (var coinGroup in orderedCoinGroups)
{
if(coin.Amount.CompareTo(target) == -1 && total.CompareTo(target) == -1)
if (coinGroup.Amount.CompareTo(target) == -1 && total.CompareTo(target) == -1)
{
total = total.Add(coin.Amount);
result.Add(coin);
total = total.Add(coinGroup.Amount);
result.AddRange(coinGroup.Coins);
//If the "sum of all your UTXO smaller than the Target" happens to match the Target, they will be used. (This is the case if you sweep a complete wallet.)
if(total.CompareTo(target) == 0)
if (total.CompareTo(target) == 0)
return result;
}
else
{
if(total.CompareTo(target) == -1 && coin.Amount.CompareTo(target) == 1)
if (total.CompareTo(target) == -1 && coinGroup.Amount.CompareTo(target) == 1)
{
//If the "sum of all your UTXO smaller than the Target" doesn't surpass the target, the smallest UTXO greater than your Target will be used.
return new[] { coin };
return coinGroup.Coins;
}
else
{
......@@ -81,27 +98,27 @@ namespace NBitcoin
//Otherwise it finally settles for the minimum of
//the smallest UTXO greater than the Target
//the smallest combination of UTXO it discovered in Step 4.
var allCoins = orderedCoins.ToArray();
var allCoins = orderedCoinGroups.ToArray();
IMoney minTotal = null;
for(int _ = 0; _ < 1000; _++)
for (int _ = 0; _ < 1000; _++)
{
var selection = new List<ICoin>();
Utils.Shuffle(allCoins, _Rand);
Utils.Shuffle(allCoins, this._Rand);
total = zero;
for(int i = 0; i < allCoins.Length; i++)
for (int i = 0; i < allCoins.Length; i++)
{
selection.Add(allCoins[i]);
selection.AddRange(allCoins[i].Coins);
total = total.Add(allCoins[i].Amount);
if(total.CompareTo(target) == 0)
if (total.CompareTo(target) == 0)
return selection;
if(total.CompareTo(target) == 1)
if (total.CompareTo(target) == 1)
break;
}
if(total.CompareTo(target) == -1)
if (total.CompareTo(target) == -1)
{
return null;
}
if(minTotal == null || total.CompareTo(minTotal) == -1)
if (minTotal == null || total.CompareTo(minTotal) == -1)
{
minTotal = total;
}
......@@ -109,7 +126,7 @@ namespace NBitcoin
}
}
}
if(total.CompareTo(target) == -1)
if (total.CompareTo(target) == -1)
return null;
return result;
}
......@@ -125,13 +142,13 @@ namespace NBitcoin
public NotEnoughFundsException(string message, string group, IMoney missing)
: base(BuildMessage(message, group, missing))
{
Missing = missing;
Group = group;
this.Missing = missing;
this.Group = group;
}
private static string BuildMessage(string message, string group, IMoney missing)
{
StringBuilder builder = new StringBuilder();
var builder = new StringBuilder();
builder.Append(message);
if(group != null)
builder.Append(" in group " + group);
......@@ -170,10 +187,10 @@ namespace NBitcoin
{
internal class TransactionBuilderSigner : ISigner
{
ICoin coin;
SigHash sigHash;
IndexedTxIn txIn;
TransactionBuilder builder;
private ICoin coin;
private SigHash sigHash;
private IndexedTxIn txIn;
private TransactionBuilder builder;
public TransactionBuilderSigner(TransactionBuilder builder, ICoin coin, SigHash sigHash, IndexedTxIn txIn)
{
this.builder = builder;
......@@ -185,31 +202,31 @@ namespace NBitcoin
public TransactionSignature Sign(Key key)
{
return txIn.Sign(this.builder.Network, key, coin, sigHash);
return this.txIn.Sign(this.builder.Network, key, this.coin, this.sigHash);
}
#endregion
}
internal class TransactionBuilderKeyRepository : IKeyRepository
{
TransactionSigningContext _Ctx;
TransactionBuilder _TxBuilder;
private TransactionSigningContext _Ctx;
private TransactionBuilder _TxBuilder;
public TransactionBuilderKeyRepository(TransactionBuilder txBuilder, TransactionSigningContext ctx)
{
_Ctx = ctx;
_TxBuilder = txBuilder;
this._Ctx = ctx;
this._TxBuilder = txBuilder;
}
#region IKeyRepository Members
public Key FindKey(Script scriptPubkey)
{
return _TxBuilder.FindKey(_Ctx, scriptPubkey);
return this._TxBuilder.FindKey(this._Ctx, scriptPubkey);
}
#endregion
}
class KnownSignatureSigner : ISigner, IKeyRepository
private class KnownSignatureSigner : ISigner, IKeyRepository
{
private ICoin coin;
private SigHash sigHash;
......@@ -217,7 +234,7 @@ namespace NBitcoin
private List<Tuple<PubKey, ECDSASignature>> _KnownSignatures;
private Dictionary<KeyId, ECDSASignature> _VerifiedSignatures = new Dictionary<KeyId, ECDSASignature>();
private Dictionary<uint256, PubKey> _DummyToRealKey = new Dictionary<uint256, PubKey>();
TransactionBuilder builder;
private TransactionBuilder builder;
public KnownSignatureSigner(TransactionBuilder builder, List<Tuple<PubKey, ECDSASignature>> _KnownSignatures, ICoin coin, SigHash sigHash, IndexedTxIn txIn)
{
......@@ -230,14 +247,14 @@ namespace NBitcoin
public Key FindKey(Script scriptPubKey)
{
foreach(var tv in _KnownSignatures.Where(tv => IsCompatibleKey(tv.Item1, scriptPubKey)))
foreach(Tuple<PubKey, ECDSASignature> tv in this._KnownSignatures.Where(tv => IsCompatibleKey(tv.Item1, scriptPubKey)))
{
var hash = txIn.GetSignatureHash(this.builder.Network, coin, sigHash);
uint256 hash = this.txIn.GetSignatureHash(this.builder.Network, this.coin, this.sigHash);
if(tv.Item1.Verify(hash, tv.Item2))
{
var key = new Key();
this._DummyToRealKey.Add(Hashes.Hash256(key.PubKey.ToBytes()), tv.Item1);
_VerifiedSignatures.AddOrReplace(key.PubKey.Hash, tv.Item2);
this._VerifiedSignatures.AddOrReplace(key.PubKey.Hash, tv.Item2);
return key;
}
}
......@@ -246,8 +263,8 @@ namespace NBitcoin
public Script ReplaceDummyKeys(Script script)
{
var ops = script.ToOps().ToList();
List<Op> result = new List<Op>();
List<Op> ops = script.ToOps().ToList();
var result = new List<Op>();
foreach(Op op in ops)
{
uint256 h = Hashes.Hash256(op.PushData);
......@@ -262,7 +279,7 @@ namespace NBitcoin
public TransactionSignature Sign(Key key)
{
return new TransactionSignature(_VerifiedSignatures[key.PubKey.Hash], sigHash);
return new TransactionSignature(this._VerifiedSignatures[key.PubKey.Hash], this.sigHash);
}
}
......@@ -270,8 +287,8 @@ namespace NBitcoin
{
public TransactionSigningContext(TransactionBuilder builder, Transaction transaction)
{
Builder = builder;
Transaction = transaction;
this.Builder = builder;
this.Transaction = transaction;
}
public Transaction Transaction
......@@ -290,7 +307,7 @@ namespace NBitcoin
{
get
{
return _AdditionalKeys;
return this._AdditionalKeys;
}
}
......@@ -300,15 +317,17 @@ namespace NBitcoin
set;
}
}
internal class TransactionBuildingContext
{
public TransactionBuildingContext(TransactionBuilder builder)
{
Builder = builder;
Transaction = builder.Network.Consensus.ConsensusFactory.CreateTransaction();
AdditionalFees = Money.Zero;
this.Builder = builder;
this.Transaction = builder.Network.CreateTransaction();
this.AdditionalFees = Money.Zero;
}
public TransactionBuilder.BuilderGroup Group
public BuilderGroup Group
{
get;
set;
......@@ -319,14 +338,16 @@ namespace NBitcoin
{
get
{
return _ConsumedCoins;
return this._ConsumedCoins;
}
}
public TransactionBuilder Builder
{
get;
set;
}
public Transaction Transaction
{
get;
......@@ -344,35 +365,34 @@ namespace NBitcoin
{
get
{
return _AdditionalBuilders;
return this._AdditionalBuilders;
}
}
ColorMarker _Marker;
private ColorMarker _Marker;
public ColorMarker GetColorMarker(bool issuance)
{
if(_Marker == null)
_Marker = new ColorMarker();
if(this._Marker == null) this._Marker = new ColorMarker();
if(!issuance)
EnsureMarkerInserted();
return _Marker;
return this._Marker;
}
private TxOut EnsureMarkerInserted()
{
uint position;
var dummy = Transaction.AddInput(new TxIn(new OutPoint(new uint256(1), 0))); //Since a transaction without input will be considered without marker, insert a dummy
TxIn dummy = this.Transaction.AddInput(new TxIn(new OutPoint(new uint256(1), 0))); //Since a transaction without input will be considered without marker, insert a dummy
try
{
if(ColorMarker.Get(Transaction, out position) != null)
return Transaction.Outputs[position];
if(ColorMarker.Get(this.Transaction, out position) != null)
return this.Transaction.Outputs[position];
}
finally
{
Transaction.Inputs.Remove(dummy);
this.Transaction.Inputs.Remove(dummy);
}
var txout = Transaction.AddOutput(new TxOut()
TxOut txout = this.Transaction.AddOutput(new TxOut()
{
ScriptPubKey = new ColorMarker().GetScript()
});
......@@ -382,10 +402,10 @@ namespace NBitcoin
public void Finish()
{
if(_Marker != null)
if(this._Marker != null)
{
var txout = EnsureMarkerInserted();
txout.ScriptPubKey = _Marker.GetScript();
TxOut txout = EnsureMarkerInserted();
txout.ScriptPubKey = this._Marker.GetScript();
}
}
......@@ -403,16 +423,16 @@ namespace NBitcoin
public TransactionBuildingContext CreateMemento()
{
var memento = new TransactionBuildingContext(Builder);
var memento = new TransactionBuildingContext(this.Builder);
memento.RestoreMemento(this);
return memento;
}
public void RestoreMemento(TransactionBuildingContext memento)
{
_Marker = memento._Marker == null ? null : new ColorMarker(memento._Marker.GetScript());
Transaction = memento.Transaction.Clone(network: memento.Builder.Network);
AdditionalFees = memento.AdditionalFees;
this._Marker = memento._Marker == null ? null : new ColorMarker(memento._Marker.GetScript());
this.Transaction = memento.Builder.Network.CreateTransaction(memento.Transaction.ToBytes());
this.AdditionalFees = memento.AdditionalFees;
}
public bool NonFinalSequenceSet
......@@ -442,15 +462,15 @@ namespace NBitcoin
internal class BuilderGroup
{
TransactionBuilder _Parent;
private TransactionBuilder _Parent;
public BuilderGroup(TransactionBuilder parent)
{
_Parent = parent;
FeeWeight = 1.0m;
Builders.Add(SetChange);
this._Parent = parent;
this.FeeWeight = 1.0m;
this.Builders.Add(SetChange);
}
IMoney SetChange(TransactionBuildingContext ctx)
private IMoney SetChange(TransactionBuildingContext ctx)
{
var changeAmount = (Money)ctx.ChangeAmount;
if(changeAmount.Satoshi == 0)
......@@ -465,14 +485,14 @@ namespace NBitcoin
internal Script[] ChangeScript = new Script[3];
internal void Shuffle()
{
Shuffle(Builders);
foreach(var builders in BuildersByAsset)
Shuffle(this.Builders);
foreach(KeyValuePair<AssetId, List<Builder>> builders in this.BuildersByAsset)
Shuffle(builders.Value);
Shuffle(IssuanceBuilders);
Shuffle(this.IssuanceBuilders);
}
private void Shuffle(List<Builder> builders)
{
Utils.Shuffle(builders, _Parent._Rand);
Utils.Shuffle(builders, this._Parent._Rand);
}
public Money CoverOnly
......@@ -494,70 +514,50 @@ namespace NBitcoin
}
}
List<BuilderGroup> _BuilderGroups = new List<BuilderGroup>();
BuilderGroup _CurrentGroup = null;
private List<BuilderGroup> _BuilderGroups = new List<BuilderGroup>();
private BuilderGroup _CurrentGroup = null;
internal BuilderGroup CurrentGroup
{
get
{
if(_CurrentGroup == null)
if(this._CurrentGroup == null)
{
_CurrentGroup = new BuilderGroup(this);
_BuilderGroups.Add(_CurrentGroup);
this._CurrentGroup = new BuilderGroup(this);
this._BuilderGroups.Add(this._CurrentGroup);
}
return _CurrentGroup;
return this._CurrentGroup;
}
}
internal TransactionBuilder()
{
this.Network = Network.Main;
_Rand = new Random();
CoinSelector = new DefaultCoinSelector();
StandardTransactionPolicy = new StandardTransactionPolicy(this.Network);
DustPrevention = true;
InitExtensions();
}
public TransactionBuilder(Network network)
{
this.Network = network;
_Rand = new Random();
CoinSelector = new DefaultCoinSelector();
StandardTransactionPolicy = new StandardTransactionPolicy(this.Network);
DustPrevention = true;
this._Rand = new Random();
this.CoinSelector = new DefaultCoinSelector();
this.StandardTransactionPolicy = new StandardTransactionPolicy(this.Network);
this.DustPrevention = true;
InitExtensions();
}
private void InitExtensions()
{
Extensions.Add(new P2PKHBuilderExtension());
Extensions.Add(new P2MultiSigBuilderExtension());
Extensions.Add(new P2PKBuilderExtension());
Extensions.Add(new OPTrueExtension());
this.Extensions.Add(new P2PKHBuilderExtension());
this.Extensions.Add(new P2MultiSigBuilderExtension());
this.Extensions.Add(new P2PKBuilderExtension());
this.Extensions.Add(new OPTrueExtension());
}
internal Random _Rand;
internal TransactionBuilder(int seed)
{
this.Network = Network.Main;
_Rand = new Random(seed);
CoinSelector = new DefaultCoinSelector(seed);
StandardTransactionPolicy = new StandardTransactionPolicy(this.Network);
DustPrevention = true;
InitExtensions();
}
public TransactionBuilder(int seed, Network network)
{
this.Network = network;
_Rand = new Random(seed);
CoinSelector = new DefaultCoinSelector(seed);
StandardTransactionPolicy = new StandardTransactionPolicy(this.Network);
DustPrevention = true;
this._Rand = new Random(seed);
this.CoinSelector = new DefaultCoinSelector(seed);
this.StandardTransactionPolicy = new StandardTransactionPolicy(this.Network);
this.DustPrevention = true;
InitExtensions();
}
......@@ -578,6 +578,7 @@ namespace NBitcoin
/// <summary>
/// Will transform transfers below Dust, so the transaction get correctly relayed by the network.
/// If true, it will remove any TxOut below Dust, so the transaction get correctly relayed by the network. (Default: true)
/// </summary>
public bool DustPrevention
{
......@@ -585,6 +586,21 @@ namespace NBitcoin
set;
}
/// <summary>
/// If true, the TransactionBuilder will not select coins whose fee to spend is higher than its value. (Default: true)
/// The cost of spending a coin is based on the <see cref="FilterUneconomicalCoinsRate"/>.
/// </summary>
public bool FilterUneconomicalCoins { get; set; } = true;
/// <summary>
/// If <see cref="FilterUneconomicalCoins"/> is true, this rate is used to know if an output is economical.
/// This property is set automatically when calling <see cref="SendEstimatedFees(FeeRate)"/> or <see cref="SendEstimatedFeesSplit(FeeRate)"/>.
/// </summary>
public FeeRate FilterUneconomicalCoinsRate
{
get; set;
}
/// <summary>
/// A callback used by the TransactionBuilder when it does not find the coin for an input
/// </summary>
......@@ -603,24 +619,24 @@ namespace NBitcoin
set;
}
LockTime? _LockTime;
private LockTime? _LockTime;
public TransactionBuilder SetLockTime(LockTime lockTime)
{
_LockTime = lockTime;
this._LockTime = lockTime;
return this;
}
List<Key> _Keys = new List<Key>();
private List<Key> _Keys = new List<Key>();
public TransactionBuilder AddKeys(params ISecret[] keys)
{
this.AddKeys(keys.Select(k => k.PrivateKey).ToArray());
AddKeys(keys.Select(k => k.PrivateKey).ToArray());
return this;
}
public TransactionBuilder AddKeys(params Key[] keys)
{
_Keys.AddRange(keys);
this._Keys.AddRange(keys);
foreach (Key k in keys)
{
AddKnownRedeems(k.PubKey.ScriptPubKey);
......@@ -636,7 +652,7 @@ namespace NBitcoin
throw new ArgumentNullException("pubKey");
if(signature == null)
throw new ArgumentNullException("signature");
_KnownSignatures.Add(Tuple.Create(pubKey, signature.Signature));
this._KnownSignatures.Add(Tuple.Create(pubKey, signature.Signature));
return this;
}
......@@ -646,7 +662,7 @@ namespace NBitcoin
throw new ArgumentNullException("pubKey");
if(signature == null)
throw new ArgumentNullException("signature");
_KnownSignatures.Add(Tuple.Create(pubKey, signature));
this._KnownSignatures.Add(Tuple.Create(pubKey, signature));
return this;
}
......@@ -657,9 +673,9 @@ namespace NBitcoin
public TransactionBuilder AddCoins(IEnumerable<ICoin> coins)
{
foreach(var coin in coins)
foreach(ICoin coin in coins)
{
CurrentGroup.Coins.AddOrReplace(coin.Outpoint, coin);
this.CurrentGroup.Coins.AddOrReplace(coin.Outpoint, coin);
}
return this;
}
......@@ -671,7 +687,7 @@ namespace NBitcoin
/// <returns></returns>
public TransactionBuilder SetGroupName(string groupName)
{
CurrentGroup.Name = groupName;
this.CurrentGroup.Name = groupName;
return this;
}
......@@ -686,7 +702,7 @@ namespace NBitcoin
return Send(destination.ScriptPubKey, amount);
}
readonly static TxNullDataTemplate _OpReturnTemplate = new TxNullDataTemplate(1024 * 1024);
private readonly static TxNullDataTemplate _OpReturnTemplate = new TxNullDataTemplate(1024 * 1024);
/// <summary>
/// Send bitcoins to a destination
......@@ -698,35 +714,35 @@ namespace NBitcoin
{
if(amount < Money.Zero)
throw new ArgumentOutOfRangeException("amount", "amount can't be negative");
_LastSendBuilder = null; //If the amount is dust, we don't want the fee to be paid by the previous Send
if(DustPrevention && amount < GetDust(scriptPubKey) && !_OpReturnTemplate.CheckScriptPubKey(this.Network, scriptPubKey))
this._LastSendBuilder = null; //If the amount is dust, we don't want the fee to be paid by the previous Send
if(this.DustPrevention && amount < GetDust(scriptPubKey) && !_OpReturnTemplate.CheckScriptPubKey(scriptPubKey))
{
SendFees(amount);
return this;
}
var builder = new SendBuilder(new TxOut(amount, scriptPubKey));
CurrentGroup.Builders.Add(builder.Build);
_LastSendBuilder = builder;
this.CurrentGroup.Builders.Add(builder.Build);
this._LastSendBuilder = builder;
return this;
}
SendBuilder _LastSendBuilder;
SendBuilder _SubstractFeeBuilder;
private SendBuilder _LastSendBuilder;
private SendBuilder _SubstractFeeBuilder;
class SendBuilder
private class SendBuilder
{
internal TxOut _TxOut;
public SendBuilder(TxOut txout)
{
_TxOut = txout;
this._TxOut = txout;
}
public Money Build(TransactionBuildingContext ctx)
{
ctx.Transaction.Outputs.Add(_TxOut);
return _TxOut.Value;
ctx.Transaction.Outputs.Add(this._TxOut);
return this._TxOut.Value;
}
}
......@@ -736,9 +752,9 @@ namespace NBitcoin
/// <returns></returns>
public TransactionBuilder SubtractFees()
{
if(_LastSendBuilder == null)
if(this._LastSendBuilder == null)
throw new InvalidOperationException("No call to TransactionBuilder.Send has been done which can support the fees");
_SubstractFeeBuilder = _LastSendBuilder;
this._SubstractFeeBuilder = this._LastSendBuilder;
return this;
}
......@@ -762,17 +778,17 @@ namespace NBitcoin
/// <exception cref="System.NotSupportedException">The coin type is not supported</exception>
public TransactionBuilder Send(Script scriptPubKey, IMoney amount)
{
MoneyBag bag = amount as MoneyBag;
var bag = amount as MoneyBag;
if(bag != null)
{
foreach(var money in bag)
foreach(IMoney money in bag)
Send(scriptPubKey, amount);
return this;
}
Money coinAmount = amount as Money;
var coinAmount = amount as Money;
if(coinAmount != null)
return Send(scriptPubKey, coinAmount);
AssetMoney assetAmount = amount as AssetMoney;
var assetAmount = amount as AssetMoney;
if(assetAmount != null)
return SendAsset(scriptPubKey, assetAmount);
throw new NotSupportedException("Type of Money not supported");
......@@ -802,20 +818,20 @@ namespace NBitcoin
public TransactionBuilder Shuffle()
{
Utils.Shuffle(_BuilderGroups, _Rand);
foreach(var group in _BuilderGroups)
Utils.Shuffle(this._BuilderGroups, this._Rand);
foreach(BuilderGroup group in this._BuilderGroups)
group.Shuffle();
return this;
}
IMoney SetColoredChange(TransactionBuildingContext ctx)
private IMoney SetColoredChange(TransactionBuildingContext ctx)
{
var changeAmount = (AssetMoney)ctx.ChangeAmount;
if(changeAmount.Quantity == 0)
return changeAmount;
var marker = ctx.GetColorMarker(false);
var script = ctx.Group.ChangeScript[(int)ChangeType.Colored];
var txout = ctx.Transaction.AddOutput(new TxOut(GetDust(script), script));
ColorMarker marker = ctx.GetColorMarker(false);
Script script = ctx.Group.ChangeScript[(int)ChangeType.Colored];
TxOut txout = ctx.Transaction.AddOutput(new TxOut(GetDust(script), script));
marker.SetQuantity(ctx.Transaction.Outputs.Count - 2, changeAmount.Quantity);
ctx.AdditionalFees += txout.Value;
return changeAmount;
......@@ -833,17 +849,17 @@ namespace NBitcoin
if(asset.Quantity == 0)
return this;
AssertOpReturn("Colored Coin");
var builders = CurrentGroup.BuildersByAsset.TryGet(asset.Id);
List<Builder> builders = this.CurrentGroup.BuildersByAsset.TryGet(asset.Id);
if(builders == null)
{
builders = new List<Builder>();
CurrentGroup.BuildersByAsset.Add(asset.Id, builders);
this.CurrentGroup.BuildersByAsset.Add(asset.Id, builders);
builders.Add(SetColoredChange);
}
builders.Add(ctx =>
{
var marker = ctx.GetColorMarker(false);
var txout = ctx.Transaction.AddOutput(new TxOut(GetDust(scriptPubKey), scriptPubKey));
ColorMarker marker = ctx.GetColorMarker(false);
TxOut txout = ctx.Transaction.AddOutput(new TxOut(GetDust(scriptPubKey), scriptPubKey));
marker.SetQuantity(ctx.Transaction.Outputs.Count - 2, asset.Quantity);
ctx.AdditionalFees += txout.Value;
return asset;
......@@ -851,15 +867,16 @@ namespace NBitcoin
return this;
}
Money GetDust()
private Money GetDust()
{
return GetDust(new Script(new byte[25]));
}
Money GetDust(Script script)
private Money GetDust(Script script)
{
if(StandardTransactionPolicy == null || StandardTransactionPolicy.MinRelayTxFee == null)
if(this.StandardTransactionPolicy == null || this.StandardTransactionPolicy.MinRelayTxFee == null)
return Money.Zero;
return new TxOut(Money.Zero, script).GetDustThreshold(StandardTransactionPolicy.MinRelayTxFee);
return new TxOut(Money.Zero, script).GetDustThreshold(this.StandardTransactionPolicy.MinRelayTxFee);
}
/// <summary>
......@@ -869,7 +886,7 @@ namespace NBitcoin
/// <returns>this</returns>
public TransactionBuilder SetTransactionPolicy(StandardTransactionPolicy policy)
{
StandardTransactionPolicy = policy;
this.StandardTransactionPolicy = policy;
return this;
}
public StandardTransactionPolicy StandardTransactionPolicy
......@@ -879,17 +896,17 @@ namespace NBitcoin
}
string _OpReturnUser;
private string _OpReturnUser;
private void AssertOpReturn(string name)
{
if(_OpReturnUser == null)
if(this._OpReturnUser == null)
{
_OpReturnUser = name;
this._OpReturnUser = name;
}
else
{
if(_OpReturnUser != name)
throw new InvalidOperationException("Op return already used for " + _OpReturnUser);
if(this._OpReturnUser != name)
throw new InvalidOperationException("Op return already used for " + this._OpReturnUser);
}
}
......@@ -898,14 +915,14 @@ namespace NBitcoin
if(amount < Money.Zero)
throw new ArgumentOutOfRangeException("amount", "amount can't be negative");
if(_OpReturnUser == null)
_OpReturnUser = "Stealth Payment";
if(this._OpReturnUser == null)
this._OpReturnUser = "Stealth Payment";
else
throw new InvalidOperationException("Op return already used for " + _OpReturnUser);
throw new InvalidOperationException("Op return already used for " + this._OpReturnUser);
CurrentGroup.Builders.Add(ctx =>
this.CurrentGroup.Builders.Add(ctx =>
{
var payment = address.CreatePayment(ephemKey);
StealthPayment payment = address.CreatePayment(ephemKey);
payment.AddToTransaction(ctx.Transaction, amount);
return amount;
});
......@@ -917,22 +934,22 @@ namespace NBitcoin
return IssueAsset(destination.ScriptPubKey, asset);
}
AssetId _IssuedAsset;
private AssetId _IssuedAsset;
public TransactionBuilder IssueAsset(Script scriptPubKey, AssetMoney asset)
{
AssertOpReturn("Colored Coin");
if(_IssuedAsset == null)
_IssuedAsset = asset.Id;
else if(_IssuedAsset != asset.Id)
if(this._IssuedAsset == null)
this._IssuedAsset = asset.Id;
else if(this._IssuedAsset != asset.Id)
throw new InvalidOperationException("You can issue only one asset type in a transaction");
CurrentGroup.IssuanceBuilders.Add(ctx =>
this.CurrentGroup.IssuanceBuilders.Add(ctx =>
{
var marker = ctx.GetColorMarker(true);
ColorMarker marker = ctx.GetColorMarker(true);
if(ctx.IssuanceCoin == null)
{
var issuance = ctx.Group.Coins.Values.OfType<IssuanceCoin>().Where(i => i.AssetId == asset.Id).FirstOrDefault();
IssuanceCoin issuance = ctx.Group.Coins.Values.OfType<IssuanceCoin>().Where(i => i.AssetId == asset.Id).FirstOrDefault();
if(issuance == null)
throw new InvalidOperationException("No issuance coin for emitting asset found");
ctx.IssuanceCoin = issuance;
......@@ -956,12 +973,12 @@ namespace NBitcoin
{
if(fees == null)
throw new ArgumentNullException("fees");
CurrentGroup.Builders.Add(ctx => fees);
_TotalFee += fees;
this.CurrentGroup.Builders.Add(ctx => fees);
this._TotalFee += fees;
return this;
}
Money _TotalFee = Money.Zero;
private Money _TotalFee = Money.Zero;
/// <summary>
/// Split the estimated fees accross the several groups (separated by Then())
......@@ -970,7 +987,8 @@ namespace NBitcoin
/// <returns></returns>
public TransactionBuilder SendEstimatedFees(FeeRate feeRate)
{
var fee = EstimateFees(feeRate);
this.FilterUneconomicalCoinsRate = feeRate;
Money fee = EstimateFees(feeRate);
SendFees(fee);
return this;
}
......@@ -982,7 +1000,8 @@ namespace NBitcoin
/// <returns></returns>
public TransactionBuilder SendEstimatedFeesSplit(FeeRate feeRate)
{
var fee = EstimateFees(feeRate);
this.FilterUneconomicalCoinsRate = feeRate;
Money fee = EstimateFees(feeRate);
SendFeesSplit(fee);
return this;
}
......@@ -996,16 +1015,16 @@ namespace NBitcoin
{
if(fees == null)
throw new ArgumentNullException("fees");
var lastGroup = CurrentGroup; //Make sure at least one group exists
var totalWeight = _BuilderGroups.Select(b => b.FeeWeight).Sum();
BuilderGroup lastGroup = this.CurrentGroup; //Make sure at least one group exists
decimal totalWeight = this._BuilderGroups.Select(b => b.FeeWeight).Sum();
Money totalSent = Money.Zero;
foreach(var group in _BuilderGroups)
foreach(BuilderGroup group in this._BuilderGroups)
{
var groupFee = Money.Satoshis((group.FeeWeight / totalWeight) * fees.Satoshi);
Money groupFee = Money.Satoshis((group.FeeWeight / totalWeight) * fees.Satoshi);
totalSent += groupFee;
if(_BuilderGroups.Last() == group)
if(this._BuilderGroups.Last() == group)
{
var leftOver = fees - totalSent;
Money leftOver = fees - totalSent;
groupFee += leftOver;
}
group.Builders.Add(ctx => groupFee);
......@@ -1021,7 +1040,7 @@ namespace NBitcoin
/// <returns></returns>
public TransactionBuilder SetFeeWeight(decimal feeWeight)
{
CurrentGroup.FeeWeight = feeWeight;
this.CurrentGroup.FeeWeight = feeWeight;
return this;
}
......@@ -1034,11 +1053,11 @@ namespace NBitcoin
{
if((changeType & ChangeType.Colored) != 0)
{
CurrentGroup.ChangeScript[(int)ChangeType.Colored] = scriptPubKey;
this.CurrentGroup.ChangeScript[(int)ChangeType.Colored] = scriptPubKey;
}
if((changeType & ChangeType.Uncolored) != 0)
{
CurrentGroup.ChangeScript[(int)ChangeType.Uncolored] = scriptPubKey;
this.CurrentGroup.ChangeScript[(int)ChangeType.Uncolored] = scriptPubKey;
}
return this;
}
......@@ -1047,9 +1066,10 @@ namespace NBitcoin
{
if(selector == null)
throw new ArgumentNullException("selector");
CoinSelector = selector;
this.CoinSelector = selector;
return this;
}
/// <summary>
/// Build the transaction
/// </summary>
......@@ -1070,30 +1090,33 @@ namespace NBitcoin
/// <exception cref="NBitcoin.NotEnoughFundsException">Not enough funds are available</exception>
public Transaction BuildTransaction(bool sign, SigHash sigHash)
{
TransactionBuildingContext ctx = new TransactionBuildingContext(this);
if(_CompletedTransaction != null)
ctx.Transaction = _CompletedTransaction.Clone(network: this.Network);
if(_LockTime != null)
ctx.Transaction.LockTime = _LockTime.Value;
foreach(var group in _BuilderGroups)
var ctx = new TransactionBuildingContext(this);
if(this._CompletedTransaction != null)
ctx.Transaction = this.Network.CreateTransaction(this._CompletedTransaction.ToBytes());
if(this._LockTime != null)
ctx.Transaction.LockTime = this._LockTime.Value;
foreach(BuilderGroup group in this._BuilderGroups)
{
ctx.Group = group;
ctx.AdditionalBuilders.Clear();
ctx.AdditionalFees = Money.Zero;
ctx.ChangeType = ChangeType.Colored;
foreach(var builder in group.IssuanceBuilders)
foreach(Builder builder in group.IssuanceBuilders)
builder(ctx);
var buildersByAsset = group.BuildersByAsset.ToList();
foreach(var builders in buildersByAsset)
List<KeyValuePair<AssetId, List<Builder>>> buildersByAsset = group.BuildersByAsset.ToList();
foreach(KeyValuePair<AssetId, List<Builder>> builders in buildersByAsset)
{
var coins = group.Coins.Values.OfType<ColoredCoin>().Where(c => c.Amount.Id == builders.Key);
IEnumerable<ColoredCoin> coins = group.Coins.Values.OfType<ColoredCoin>().Where(c => c.Amount.Id == builders.Key);
ctx.Dust = new AssetMoney(builders.Key);
ctx.CoverOnly = null;
ctx.ChangeAmount = new AssetMoney(builders.Key);
var btcSpent = BuildTransaction(ctx, group, builders.Value, coins, new AssetMoney(builders.Key))
Money btcSpent = BuildTransaction(ctx, group, builders.Value, coins, new AssetMoney(builders.Key))
.OfType<IColoredCoin>().Select(c => c.Bearer.Amount).Sum();
ctx.AdditionalFees -= btcSpent;
}
......@@ -1103,17 +1126,32 @@ namespace NBitcoin
ctx.ChangeAmount = Money.Zero;
ctx.CoverOnly = group.CoverOnly;
ctx.ChangeType = ChangeType.Uncolored;
BuildTransaction(ctx, group, group.Builders, group.Coins.Values.OfType<Coin>(), Money.Zero);
BuildTransaction(ctx, group, group.Builders, group.Coins.Values.OfType<Coin>().Where(IsEconomical), Money.Zero);
}
ctx.Finish();
if(sign)
{
SignTransactionInPlace(ctx.Transaction, sigHash);
}
return ctx.Transaction;
}
private bool IsEconomical(Coin c)
{
if (!this.FilterUneconomicalCoins || this.FilterUneconomicalCoinsRate == null)
return true;
int witSize = 0;
int baseSize = 0;
EstimateScriptSigSize(c, ref witSize, ref baseSize);
var vSize = witSize / Transaction.WITNESS_SCALE_FACTOR + baseSize;
return c.Amount >= this.FilterUneconomicalCoinsRate.GetFee(vSize);
}
private IEnumerable<ICoin> BuildTransaction(
TransactionBuildingContext ctx,
BuilderGroup group,
......@@ -1121,48 +1159,56 @@ namespace NBitcoin
IEnumerable<ICoin> coins,
IMoney zero)
{
var originalCtx = ctx.CreateMemento();
var fees = _TotalFee + ctx.AdditionalFees;
TransactionBuildingContext originalCtx = ctx.CreateMemento();
Money fees = this._TotalFee + ctx.AdditionalFees;
// Replace the _SubstractFeeBuilder by another one with the fees substracts
var builderList = builders.ToList();
List<Builder> builderList = builders.ToList();
for(int i = 0; i < builderList.Count; i++)
{
if(builderList[i].Target == _SubstractFeeBuilder)
if(builderList[i].Target == this._SubstractFeeBuilder)
{
builderList.Remove(builderList[i]);
var newTxOut = _SubstractFeeBuilder._TxOut.Clone(network: this.Network);
TxOut newTxOut = this._SubstractFeeBuilder._TxOut.Clone();
newTxOut.Value -= fees;
builderList.Insert(i, new SendBuilder(newTxOut).Build);
}
}
////////////////////////////////////////////////////////
var target = builderList.Concat(ctx.AdditionalBuilders).Select(b => b(ctx)).Sum(zero);
IMoney target = builderList.Concat(ctx.AdditionalBuilders).Select(b => b(ctx)).Sum(zero);
if(ctx.CoverOnly != null)
{
target = ctx.CoverOnly.Add(ctx.ChangeAmount);
}
var unconsumed = coins.Where(c => ctx.ConsumedCoins.All(cc => cc.Outpoint != c.Outpoint));
var selection = CoinSelector.Select(unconsumed, target);
IEnumerable<ICoin> unconsumed = coins.Where(c => ctx.ConsumedCoins.All(cc => cc.Outpoint != c.Outpoint));
IEnumerable<ICoin> selection = this.CoinSelector.Select(unconsumed, target);
if(selection == null)
{
throw new NotEnoughFundsException("Not enough funds to cover the target",
group.Name,
target.Sub(unconsumed.Select(u => u.Amount).Sum(zero))
);
var total = selection.Select(s => s.Amount).Sum(zero);
var change = total.Sub(target);
}
IMoney total = selection.Select(s => s.Amount).Sum(zero);
IMoney change = total.Sub(target);
if(change.CompareTo(zero) == -1)
{
throw new NotEnoughFundsException("Not enough funds to cover the target",
group.Name,
change.Negate()
);
}
if(change.CompareTo(ctx.Dust) == 1)
{
var changeScript = group.ChangeScript[(int)ctx.ChangeType];
Script changeScript = group.ChangeScript[(int)ctx.ChangeType];
if(changeScript == null)
throw new InvalidOperationException("A change address should be specified (" + ctx.ChangeType + ")");
if(!(ctx.Dust is Money) || change.CompareTo(GetDust(changeScript)) == 1)
{
ctx.RestoreMemento(originalCtx);
......@@ -1177,24 +1223,26 @@ namespace NBitcoin
}
}
}
foreach(var coin in selection)
foreach(ICoin coin in selection)
{
ctx.ConsumedCoins.Add(coin);
var input = ctx.Transaction.Inputs.FirstOrDefault(i => i.PrevOut == coin.Outpoint);
TxIn input = ctx.Transaction.Inputs.FirstOrDefault(i => i.PrevOut == coin.Outpoint);
if(input == null)
input = ctx.Transaction.AddInput(new TxIn(coin.Outpoint));
if(_LockTime != null && !ctx.NonFinalSequenceSet)
if(this._LockTime != null && !ctx.NonFinalSequenceSet)
{
input.Sequence = 0;
ctx.NonFinalSequenceSet = true;
}
}
return selection;
}
public Transaction SignTransaction(Transaction transaction, SigHash sigHash)
{
var tx = transaction.Clone(network: this.Network);
Transaction tx = this.Network.CreateTransaction(transaction.ToBytes());
SignTransactionInPlace(tx, sigHash);
return tx;
}
......@@ -1203,17 +1251,22 @@ namespace NBitcoin
{
return SignTransaction(transaction, SigHash.All);
}
public Transaction SignTransactionInPlace(Transaction transaction)
{
return SignTransactionInPlace(transaction, SigHash.All);
}
public Transaction SignTransactionInPlace(Transaction transaction, SigHash sigHash)
{
TransactionSigningContext ctx = new TransactionSigningContext(this, transaction);
ctx.SigHash = sigHash;
foreach(var input in transaction.Inputs.AsIndexedInputs())
var ctx = new TransactionSigningContext(this, transaction)
{
var coin = FindSignableCoin(input);
SigHash = sigHash
};
foreach (IndexedTxIn input in transaction.Inputs.AsIndexedInputs())
{
ICoin coin = FindSignableCoin(input);
if(coin != null)
{
Sign(ctx, coin, input);
......@@ -1224,25 +1277,27 @@ namespace NBitcoin
public ICoin FindSignableCoin(IndexedTxIn txIn)
{
var coin = FindCoin(txIn.PrevOut);
ICoin coin = FindCoin(txIn.PrevOut);
if(coin is IColoredCoin)
coin = ((IColoredCoin)coin).Bearer;
if(coin == null || coin is ScriptCoin || coin is StealthCoin)
return coin;
var hash = ScriptCoin.GetRedeemHash(this.Network, coin.TxOut.ScriptPubKey);
TxDestination hash = ScriptCoin.GetRedeemHash(this.Network, coin.TxOut.ScriptPubKey);
if(hash != null)
{
var redeem = _ScriptPubKeyToRedeem.TryGet(coin.TxOut.ScriptPubKey);
if(redeem != null && PayToWitScriptHashTemplate.Instance.CheckScriptPubKey(this.Network, redeem))
redeem = _ScriptPubKeyToRedeem.TryGet(redeem);
Script redeem = this._ScriptPubKeyToRedeem.TryGet(coin.TxOut.ScriptPubKey);
if(redeem != null && PayToWitScriptHashTemplate.Instance.CheckScriptPubKey(redeem))
redeem = this._ScriptPubKeyToRedeem.TryGet(redeem);
if(redeem == null)
{
if(hash is WitScriptId)
redeem = PayToWitScriptHashTemplate.Instance.ExtractWitScriptParameters(txIn.WitScript, (WitScriptId)hash);
if(hash is ScriptId)
{
var parameters = PayToScriptHashTemplate.Instance.ExtractScriptSigParameters(this.Network, txIn.ScriptSig, (ScriptId)hash);
PayToScriptHashSigParameters parameters = PayToScriptHashTemplate.Instance.ExtractScriptSigParameters(this.Network, txIn.ScriptSig, (ScriptId)hash);
if(parameters != null)
redeem = parameters.RedeemScript;
}
......@@ -1308,19 +1363,19 @@ namespace NBitcoin
{
if(tx == null)
throw new ArgumentNullException("tx");
var coins = tx.Inputs.Select(i => FindCoin(i.PrevOut)).Where(c => c != null).ToArray();
List<TransactionPolicyError> exceptions = new List<TransactionPolicyError>();
var policyErrors = MinerTransactionPolicy.Instance.Check(tx, coins);
ICoin[] coins = tx.Inputs.Select(i => FindCoin(i.PrevOut)).Where(c => c != null).ToArray();
var exceptions = new List<TransactionPolicyError>();
TransactionPolicyError[] policyErrors = MinerTransactionPolicy.Instance.Check(tx, coins);
exceptions.AddRange(policyErrors);
policyErrors = StandardTransactionPolicy.Check(tx, coins);
policyErrors = this.StandardTransactionPolicy.Check(tx, coins);
exceptions.AddRange(policyErrors);
if(expectedFees != null)
{
var fees = tx.GetFee(coins);
Money fees = tx.GetFee(coins);
if(fees != null)
{
Money margin = Money.Zero;
if(DustPrevention)
if(this.DustPrevention)
margin = GetDust() * 2;
if(!fees.Almost(expectedFees, margin))
exceptions.Add(new NotEnoughFundsPolicyError("Fees different than expected", expectedFees - fees));
......@@ -1382,9 +1437,9 @@ namespace NBitcoin
public ICoin FindCoin(OutPoint outPoint)
{
var result = _BuilderGroups.Select(c => c.Coins.TryGet(outPoint)).FirstOrDefault(r => r != null);
if(result == null && CoinFinder != null)
result = CoinFinder(outPoint);
ICoin result = this._BuilderGroups.Select(c => c.Coins.TryGet(outPoint)).FirstOrDefault(r => r != null);
if(result == null && this.CoinFinder != null)
result = this.CoinFinder(outPoint);
return result;
}
......@@ -1420,56 +1475,55 @@ namespace NBitcoin
/// <returns></returns>
public int EstimateSize(Transaction tx, bool virtualSize)
{
if(tx == null)
if (tx == null)
throw new ArgumentNullException("tx");
var clone = tx.Clone(network:this.Network);
Transaction clone = this.Network.CreateTransaction(tx.ToHex());
clone.Inputs.Clear();
var baseSize = clone.GetSerializedSize();
int baseSize = clone.GetSerializedSize();
int vSize = 0;
int size = baseSize;
if(tx.HasWitness)
vSize += 2;
foreach(var txin in tx.Inputs.AsIndexedInputs())
int witSize = 0;
if (tx.HasWitness)
witSize += 2;
foreach (var txin in tx.Inputs.AsIndexedInputs())
{
var coin = FindSignableCoin(txin) ?? FindCoin(txin.PrevOut);
if(coin == null)
ICoin coin = FindSignableCoin(txin) ?? FindCoin(txin.PrevOut);
if (coin == null)
throw CoinNotFound(txin);
EstimateScriptSigSize(coin, ref vSize, ref size);
size += 41;
EstimateScriptSigSize(coin, ref witSize, ref baseSize);
baseSize += 41;
}
return (virtualSize ? vSize / Transaction.WITNESS_SCALE_FACTOR + size : vSize + size);
return (virtualSize ? witSize / Transaction.WITNESS_SCALE_FACTOR + baseSize : witSize + baseSize);
}
private void EstimateScriptSigSize(ICoin coin, ref int vSize, ref int size)
private void EstimateScriptSigSize(ICoin coin, ref int witSize, ref int baseSize)
{
if(coin is IColoredCoin)
if (coin is IColoredCoin)
coin = ((IColoredCoin)coin).Bearer;
if(coin is ScriptCoin)
if (coin is ScriptCoin scriptCoin)
{
var scriptCoin = (ScriptCoin)coin;
var p2sh = scriptCoin.GetP2SHRedeem();
if(p2sh != null)
Script p2sh = scriptCoin.GetP2SHRedeem();
if (p2sh != null)
{
coin = new Coin(scriptCoin.Outpoint, new TxOut(scriptCoin.Amount, p2sh));
size += new Script(Op.GetPushOp(p2sh.ToBytes(true))).Length;
if(scriptCoin.RedeemType == RedeemType.WitnessV0)
baseSize += new Script(Op.GetPushOp(p2sh.ToBytes(true))).Length;
if (scriptCoin.RedeemType == RedeemType.WitnessV0)
{
coin = new ScriptCoin(coin, scriptCoin.Redeem);
}
}
if(scriptCoin.RedeemType == RedeemType.WitnessV0)
if (scriptCoin.RedeemType == RedeemType.WitnessV0)
{
vSize += new Script(Op.GetPushOp(scriptCoin.Redeem.ToBytes(true))).Length;
witSize += new Script(Op.GetPushOp(scriptCoin.Redeem.ToBytes(true))).Length;
}
}
var scriptPubkey = coin.GetScriptCode(this.Network);
var scriptSigSize = -1;
foreach(var extension in Extensions)
Script scriptPubkey = coin.GetScriptCode(this.Network);
int scriptSigSize = -1;
foreach(BuilderExtension extension in this.Extensions)
{
if(extension.CanEstimateScriptSigSize(this.Network, scriptPubkey))
{
......@@ -1478,12 +1532,13 @@ namespace NBitcoin
}
}
if(scriptSigSize == -1)
if (scriptSigSize == -1)
scriptSigSize += coin.TxOut.ScriptPubKey.Length; //Using heurestic to approximate size of unknown scriptPubKey
if(coin.GetHashVersion(this.Network) == HashVersion.Witness)
vSize += scriptSigSize + 1; //Account for the push
witSize += scriptSigSize + 1; //Account for the push
if(coin.GetHashVersion(this.Network) == HashVersion.Original)
size += scriptSigSize;
baseSize += scriptSigSize;
}
/// <summary>
......@@ -1496,15 +1551,15 @@ namespace NBitcoin
if(feeRate == null)
throw new ArgumentNullException("feeRate");
int builderCount = CurrentGroup.Builders.Count;
int builderCount = this.CurrentGroup.Builders.Count;
Money feeSent = Money.Zero;
try
{
while(true)
{
var tx = BuildTransaction(false);
var shouldSend = EstimateFees(tx, feeRate);
var delta = shouldSend - feeSent;
Transaction tx = BuildTransaction(false);
Money shouldSend = EstimateFees(tx, feeRate);
Money delta = shouldSend - feeSent;
if(delta <= Money.Zero)
break;
SendFees(delta);
......@@ -1513,9 +1568,9 @@ namespace NBitcoin
}
finally
{
while(CurrentGroup.Builders.Count != builderCount)
while(this.CurrentGroup.Builders.Count != builderCount)
{
CurrentGroup.Builders.RemoveAt(CurrentGroup.Builders.Count - 1);
this.CurrentGroup.Builders.RemoveAt(this.CurrentGroup.Builders.Count - 1);
}
this._TotalFee -= feeSent;
}
......@@ -1535,30 +1590,30 @@ namespace NBitcoin
if(feeRate == null)
throw new ArgumentNullException("feeRate");
var estimation = EstimateSize(tx, true);
int estimation = EstimateSize(tx, true);
return feeRate.GetFee(estimation);
}
private void Sign(TransactionSigningContext ctx, ICoin coin, IndexedTxIn txIn)
{
var input = txIn.TxIn;
TxIn input = txIn.TxIn;
if(coin is StealthCoin)
{
var stealthCoin = (StealthCoin)coin;
var scanKey = FindKey(ctx, stealthCoin.Address.ScanPubKey.ScriptPubKey);
Key scanKey = FindKey(ctx, stealthCoin.Address.ScanPubKey.ScriptPubKey);
if(scanKey == null)
throw new KeyNotFoundException("Scan key for decrypting StealthCoin not found");
var spendKeys = stealthCoin.Address.SpendPubKeys.Select(p => FindKey(ctx, p.ScriptPubKey)).Where(p => p != null).ToArray();
Key[] spendKeys = stealthCoin.Address.SpendPubKeys.Select(p => FindKey(ctx, p.ScriptPubKey)).Where(p => p != null).ToArray();
ctx.AdditionalKeys.AddRange(stealthCoin.Uncover(spendKeys, scanKey));
var normalCoin = new Coin(coin.Outpoint, coin.TxOut);
if(stealthCoin.Redeem != null)
normalCoin = normalCoin.ToScriptCoin(stealthCoin.Redeem);
coin = normalCoin;
}
var scriptSig = CreateScriptSig(ctx, coin, txIn);
Script scriptSig = CreateScriptSig(ctx, coin, txIn);
if(scriptSig == null)
return;
ScriptCoin scriptCoin = coin as ScriptCoin;
var scriptCoin = coin as ScriptCoin;
Script signatures = null;
if(coin.GetHashVersion(this.Network) == HashVersion.Witness)
......@@ -1608,19 +1663,19 @@ namespace NBitcoin
{
if(script == Script.Empty)
return script;
var ops = script.ToOps().ToArray();
Op[] ops = script.ToOps().ToArray();
return new Script(ops.Take(ops.Length - 1));
}
private Script CombineScriptSigs(ICoin coin, Script a, Script b)
{
var scriptPubkey = coin.GetScriptCode(this.Network);
Script scriptPubkey = coin.GetScriptCode(this.Network);
if(Script.IsNullOrEmpty(a))
return b ?? Script.Empty;
if(Script.IsNullOrEmpty(b))
return a ?? Script.Empty;
foreach(var extension in Extensions)
foreach(BuilderExtension extension in this.Extensions)
{
if(extension.CanCombineScriptSig(this.Network, scriptPubkey, a, b))
{
......@@ -1632,25 +1687,25 @@ namespace NBitcoin
private Script CreateScriptSig(TransactionSigningContext ctx, ICoin coin, IndexedTxIn txIn)
{
var scriptPubKey = coin.GetScriptCode(this.Network);
Script scriptPubKey = coin.GetScriptCode(this.Network);
var keyRepo = new TransactionBuilderKeyRepository(this, ctx);
var signer = new TransactionBuilderSigner(this, coin, ctx.SigHash, txIn);
var signer2 = new KnownSignatureSigner(this, _KnownSignatures, coin, ctx.SigHash, txIn);
var signer2 = new KnownSignatureSigner(this, this._KnownSignatures, coin, ctx.SigHash, txIn);
foreach(var extension in Extensions)
foreach(BuilderExtension extension in this.Extensions)
{
if(extension.CanGenerateScriptSig(this.Network, scriptPubKey))
{
var scriptSig1 = extension.GenerateScriptSig(this.Network, scriptPubKey, keyRepo, signer);
var scriptSig2 = extension.GenerateScriptSig(this.Network, scriptPubKey, signer2, signer2);
Script scriptSig1 = extension.GenerateScriptSig(this.Network, scriptPubKey, keyRepo, signer);
Script scriptSig2 = extension.GenerateScriptSig(this.Network, scriptPubKey, signer2, signer2);
if (scriptSig2 != null)
{
scriptSig2 = signer2.ReplaceDummyKeys(scriptSig2);
}
if (scriptSig1 != null && scriptSig2 != null && extension.CanCombineScriptSig(this.Network, scriptPubKey, scriptSig1, scriptSig2))
{
var combined = extension.CombineScriptSig(this.Network, scriptPubKey, scriptSig1, scriptSig2);
Script combined = extension.CombineScriptSig(this.Network, scriptPubKey, scriptSig1, scriptSig2);
return combined;
}
return scriptSig1 ?? scriptSig2;
......@@ -1660,16 +1715,16 @@ namespace NBitcoin
throw new NotSupportedException("Unsupported scriptPubKey");
}
List<Tuple<PubKey, ECDSASignature>> _KnownSignatures = new List<Tuple<PubKey, ECDSASignature>>();
private List<Tuple<PubKey, ECDSASignature>> _KnownSignatures = new List<Tuple<PubKey, ECDSASignature>>();
private Key FindKey(TransactionSigningContext ctx, Script scriptPubKey)
{
var key = _Keys
Key key = this._Keys
.Concat(ctx.AdditionalKeys)
.FirstOrDefault(k => IsCompatibleKey(k.PubKey, scriptPubKey));
if(key == null && KeyFinder != null)
if(key == null && this.KeyFinder != null)
{
key = KeyFinder(scriptPubKey);
key = this.KeyFinder(scriptPubKey);
}
return key;
}
......@@ -1688,7 +1743,7 @@ namespace NBitcoin
/// <returns></returns>
public TransactionBuilder Then()
{
_CurrentGroup = null;
this._CurrentGroup = null;
return this;
}
......@@ -1698,14 +1753,15 @@ namespace NBitcoin
/// <returns></returns>
public TransactionBuilder Then(string groupName)
{
var group = _BuilderGroups.FirstOrDefault(g => g.Name == groupName);
BuilderGroup group = this._BuilderGroups.FirstOrDefault(g => g.Name == groupName);
if(group == null)
{
group = new BuilderGroup(this);
_BuilderGroups.Add(group);
this._BuilderGroups.Add(group);
group.Name = groupName;
}
_CurrentGroup = group;
this._CurrentGroup = group;
return this;
}
......@@ -1716,12 +1772,12 @@ namespace NBitcoin
/// <returns></returns>
public TransactionBuilder CoverOnly(Money amount)
{
CurrentGroup.CoverOnly = amount;
this.CurrentGroup.CoverOnly = amount;
return this;
}
Transaction _CompletedTransaction;
private Transaction _CompletedTransaction;
/// <summary>
/// Allows to keep building on the top of a partially built transaction
......@@ -1730,9 +1786,11 @@ namespace NBitcoin
/// <returns></returns>
public TransactionBuilder ContinueToBuild(Transaction transaction)
{
if(_CompletedTransaction != null)
if(this._CompletedTransaction != null)
throw new InvalidOperationException("Transaction to complete already set");
_CompletedTransaction = transaction.Clone(network:this.Network);
this._CompletedTransaction = this.Network.CreateTransaction(transaction.ToHex());
return this;
}
......@@ -1742,12 +1800,12 @@ namespace NBitcoin
/// <returns></returns>
public TransactionBuilder CoverTheRest()
{
if(_CompletedTransaction == null)
if(this._CompletedTransaction == null)
throw new InvalidOperationException("A partially built transaction should be specified by calling ContinueToBuild");
var spent = _CompletedTransaction.Inputs.AsIndexedInputs().Select(txin =>
Money spent = this._CompletedTransaction.Inputs.AsIndexedInputs().Select(txin =>
{
var c = FindCoin(txin.PrevOut);
ICoin c = FindCoin(txin.PrevOut);
if(c == null)
throw CoinNotFound(txin);
if(!(c is Coin))
......@@ -1758,8 +1816,8 @@ namespace NBitcoin
.Select(c => c.Amount)
.Sum();
var toComplete = _CompletedTransaction.TotalOut - spent;
CurrentGroup.Builders.Add(ctx =>
Money toComplete = this._CompletedTransaction.TotalOut - spent;
this.CurrentGroup.Builders.Add(ctx =>
{
if(toComplete < Money.Zero)
return Money.Zero;
......@@ -1770,19 +1828,19 @@ namespace NBitcoin
public TransactionBuilder AddCoins(Transaction transaction)
{
var txId = transaction.GetHash();
uint256 txId = transaction.GetHash();
AddCoins(transaction.Outputs.Select((o, i) => new Coin(txId, (uint)i, o.Value, o.ScriptPubKey)).ToArray());
return this;
}
Dictionary<Script, Script> _ScriptPubKeyToRedeem = new Dictionary<Script, Script>();
private Dictionary<Script, Script> _ScriptPubKeyToRedeem = new Dictionary<Script, Script>();
public TransactionBuilder AddKnownRedeems(params Script[] knownRedeems)
{
foreach(var redeem in knownRedeems)
foreach(Script redeem in knownRedeems)
{
_ScriptPubKeyToRedeem.AddOrReplace(redeem.WitHash.ScriptPubKey.Hash.ScriptPubKey, redeem); //Might be P2SH(PWSH)
_ScriptPubKeyToRedeem.AddOrReplace(redeem.Hash.ScriptPubKey, redeem); //Might be P2SH
_ScriptPubKeyToRedeem.AddOrReplace(redeem.WitHash.ScriptPubKey, redeem); //Might be PWSH
this._ScriptPubKeyToRedeem.AddOrReplace(redeem.WitHash.ScriptPubKey.Hash.ScriptPubKey, redeem); //Might be P2SH(PWSH)
this._ScriptPubKeyToRedeem.AddOrReplace(redeem.Hash.ScriptPubKey, redeem); //Might be P2SH
this._ScriptPubKeyToRedeem.AddOrReplace(redeem.WitHash.ScriptPubKey, redeem); //Might be PWSH
}
return this;
}
......@@ -1791,25 +1849,25 @@ namespace NBitcoin
{
if(transactions.Length == 1)
return transactions[0];
if(transactions.Length == 0)
return null;
Transaction tx = transactions[0].Clone(network: this.Network);
Transaction tx = this.Network.CreateTransaction(transactions[0].ToHex());
for(int i = 1; i < transactions.Length; i++)
{
var signed = transactions[i];
Transaction signed = transactions[i];
tx = CombineSignaturesCore(tx, signed);
}
return tx;
}
private readonly List<BuilderExtension> _Extensions = new List<BuilderExtension>();
public List<BuilderExtension> Extensions
{
get
{
return _Extensions;
return this._Extensions;
}
}
......@@ -1817,31 +1875,33 @@ namespace NBitcoin
{
if(signed1 == null)
return signed2;
if(signed2 == null)
return signed1;
var tx = signed1.Clone(network: this.Network);
Transaction tx = this.Network.CreateTransaction(signed1.ToHex());
for(int i = 0; i < tx.Inputs.Count; i++)
{
if(i >= signed2.Inputs.Count)
break;
var txIn = tx.Inputs[i];
TxIn txIn = tx.Inputs[i];
var coin = FindCoin(txIn.PrevOut);
var scriptPubKey = coin == null
ICoin coin = FindCoin(txIn.PrevOut);
Script scriptPubKey = coin == null
? (DeduceScriptPubKey(txIn.ScriptSig) ?? DeduceScriptPubKey(signed2.Inputs[i].ScriptSig))
: coin.TxOut.ScriptPubKey;
Money amount = null;
if(coin != null)
amount = coin is IColoredCoin ? ((IColoredCoin)coin).Bearer.Amount : ((Coin)coin).Amount;
var result = Script.CombineSignatures(
ScriptSigs result = Script.CombineSignatures(
this.Network,
scriptPubKey,
new TransactionChecker(tx, i, amount),
GetScriptSigs(signed1.Inputs.AsIndexedInputs().Skip(i).First()),
GetScriptSigs(signed2.Inputs.AsIndexedInputs().Skip(i).First()));
var input = tx.Inputs.AsIndexedInputs().Skip(i).First();
IndexedTxIn input = tx.Inputs.AsIndexedInputs().Skip(i).First();
input.WitScript = result.WitSig;
input.ScriptSig = result.ScriptSig;
}
......@@ -1859,12 +1919,12 @@ namespace NBitcoin
private Script DeduceScriptPubKey(Script scriptSig)
{
var p2sh = PayToScriptHashTemplate.Instance.ExtractScriptSigParameters(this.Network, scriptSig);
PayToScriptHashSigParameters p2sh = PayToScriptHashTemplate.Instance.ExtractScriptSigParameters(this.Network, scriptSig);
if(p2sh != null && p2sh.RedeemScript != null)
{
return p2sh.RedeemScript.Hash.ScriptPubKey;
}
foreach(var extension in Extensions)
foreach(BuilderExtension extension in this.Extensions)
{
if(extension.CanDeduceScriptPubKey(this.Network, scriptSig))
{
......@@ -1880,8 +1940,8 @@ namespace NBitcoin
public CoinNotFoundException(IndexedTxIn txIn)
: base("No coin matching " + txIn.PrevOut + " was found")
{
_OutPoint = txIn.PrevOut;
_InputIndex = txIn.Index;
this._OutPoint = txIn.PrevOut;
this._InputIndex = txIn.Index;
}
private readonly OutPoint _OutPoint;
......@@ -1889,7 +1949,7 @@ namespace NBitcoin
{
get
{
return _OutPoint;
return this._OutPoint;
}
}
......@@ -1898,7 +1958,7 @@ namespace NBitcoin
{
get
{
return _InputIndex;
return this._InputIndex;
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment