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

Modify project NBitcoin

parent 2edbb663
...@@ -16,7 +16,7 @@ namespace NBitcoin ...@@ -16,7 +16,7 @@ namespace NBitcoin
public class Scope : IDisposable public class Scope : IDisposable
{ {
Action close; private Action close;
public Scope(Action open, Action close) public Scope(Action open, Action close)
{ {
this.close = close; this.close = close;
...@@ -27,7 +27,7 @@ namespace NBitcoin ...@@ -27,7 +27,7 @@ namespace NBitcoin
public void Dispose() public void Dispose()
{ {
close(); this.close();
} }
#endregion #endregion
...@@ -48,7 +48,7 @@ namespace NBitcoin ...@@ -48,7 +48,7 @@ namespace NBitcoin
// TODO: Make NetworkOptions required in the constructors of this class. // TODO: Make NetworkOptions required in the constructors of this class.
public partial class BitcoinStream public partial class BitcoinStream
{ {
int maxArraySize = 1024 * 1024; private int maxArraySize = 1024 * 1024;
public int MaxArraySize public int MaxArraySize
{ {
get get
...@@ -62,7 +62,7 @@ namespace NBitcoin ...@@ -62,7 +62,7 @@ namespace NBitcoin
} }
//ReadWrite<T>(ref T data) //ReadWrite<T>(ref T data)
static MethodInfo readWriteTyped; private static MethodInfo readWriteTyped;
static BitcoinStream() static BitcoinStream()
{ {
readWriteTyped = typeof(BitcoinStream) readWriteTyped = typeof(BitcoinStream)
...@@ -95,6 +95,7 @@ namespace NBitcoin ...@@ -95,6 +95,7 @@ namespace NBitcoin
public BitcoinStream(Stream inner, bool serializing) public BitcoinStream(Stream inner, bool serializing)
{ {
this.ConsensusFactory = new DefaultConsensusFactory();
this.serializing = serializing; this.serializing = serializing;
this.inner = inner; this.inner = inner;
} }
...@@ -138,12 +139,12 @@ namespace NBitcoin ...@@ -138,12 +139,12 @@ namespace NBitcoin
{ {
if (this.Serializing) if (this.Serializing)
{ {
VarString str = new VarString(bytes); var str = new VarString(bytes);
str.ReadWrite(this); str.ReadWrite(this);
} }
else else
{ {
VarString str = new VarString(); var str = new VarString();
str.ReadWrite(this); str.ReadWrite(this);
bytes = str.GetString(true); bytes = str.GetString(true);
} }
...@@ -193,12 +194,14 @@ namespace NBitcoin ...@@ -193,12 +194,14 @@ namespace NBitcoin
public void ReadWrite<T>(ref T data) where T : IBitcoinSerializable public void ReadWrite<T>(ref T data) where T : IBitcoinSerializable
{ {
var obj = data; T obj = data;
if (obj == null) if (obj == null)
{ {
if (!this.ConsensusFactory.TryCreateNew<T>(out obj)) obj = this.ConsensusFactory.TryCreateNew<T>();
if (obj == null)
obj = Activator.CreateInstance<T>(); obj = Activator.CreateInstance<T>();
} }
obj.ReadWrite(this); obj.ReadWrite(this);
if (!this.Serializing) if (!this.Serializing)
data = obj; data = obj;
...@@ -220,7 +223,7 @@ namespace NBitcoin ...@@ -220,7 +223,7 @@ namespace NBitcoin
where TList : List<TItem>, new() where TList : List<TItem>, new()
where TItem : IBitcoinSerializable, new() where TItem : IBitcoinSerializable, new()
{ {
var dataArray = data == null ? null : data.ToArray(); TItem[] dataArray = data == null ? null : data.ToArray();
if (this.Serializing && dataArray == null) if (this.Serializing && dataArray == null)
{ {
...@@ -241,7 +244,7 @@ namespace NBitcoin ...@@ -241,7 +244,7 @@ namespace NBitcoin
public void ReadWrite(ref byte[] arr) public void ReadWrite(ref byte[] arr)
{ {
this.ReadWriteBytes(ref arr); ReadWriteBytes(ref arr);
} }
public void ReadWrite(ref byte[] arr, int offset, int count) public void ReadWrite(ref byte[] arr, int offset, int count)
...@@ -265,7 +268,7 @@ namespace NBitcoin ...@@ -265,7 +268,7 @@ namespace NBitcoin
{ {
var bytes = new byte[size]; 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); bytes[i] = (byte)(value >> i * 8);
} }
...@@ -277,7 +280,7 @@ namespace NBitcoin ...@@ -277,7 +280,7 @@ namespace NBitcoin
ulong valueTemp = 0; ulong valueTemp = 0;
for (int i = 0; i < bytes.Length; i++) for (int i = 0; i < bytes.Length; i++)
{ {
var v = (ulong)bytes[i]; ulong v = (ulong)bytes[i];
valueTemp += v << (i * 8); valueTemp += v << (i * 8);
} }
value = valueTemp; value = valueTemp;
...@@ -300,7 +303,7 @@ namespace NBitcoin ...@@ -300,7 +303,7 @@ namespace NBitcoin
} }
else else
{ {
var readen = this.Inner.ReadEx(data, offset, count, this.ReadCancellationToken); int readen = this.Inner.ReadEx(data, offset, count, this.ReadCancellationToken);
if (readen == 0) if (readen == 0)
throw new EndOfStreamException("No more byte to read"); throw new EndOfStreamException("No more byte to read");
this.Counter.AddRead(readen); this.Counter.AddRead(readen);
...@@ -328,7 +331,7 @@ namespace NBitcoin ...@@ -328,7 +331,7 @@ namespace NBitcoin
} }
else else
{ {
var readen = this.Inner.ReadByte(); int readen = this.Inner.ReadByte();
if (readen == -1) if (readen == -1)
throw new EndOfStreamException("No more byte to read"); throw new EndOfStreamException("No more byte to read");
data = (byte)readen; data = (byte)readen;
...@@ -344,7 +347,7 @@ namespace NBitcoin ...@@ -344,7 +347,7 @@ namespace NBitcoin
public IDisposable BigEndianScope() public IDisposable BigEndianScope()
{ {
var old = this.IsBigEndian; bool old = this.IsBigEndian;
return new Scope(() => return new Scope(() =>
{ {
this.IsBigEndian = true; this.IsBigEndian = true;
...@@ -355,7 +358,7 @@ namespace NBitcoin ...@@ -355,7 +358,7 @@ namespace NBitcoin
}); });
} }
ProtocolVersion protocolVersion = ProtocolVersion.PROTOCOL_VERSION; private ProtocolVersion protocolVersion = ProtocolVersion.PROTOCOL_VERSION;
public ProtocolVersion ProtocolVersion public ProtocolVersion ProtocolVersion
{ {
get get
...@@ -368,7 +371,7 @@ namespace NBitcoin ...@@ -368,7 +371,7 @@ namespace NBitcoin
} }
} }
TransactionOptions transactionSupportedOptions = TransactionOptions.All; private TransactionOptions transactionSupportedOptions = TransactionOptions.All;
public TransactionOptions TransactionOptions public TransactionOptions TransactionOptions
{ {
get get
...@@ -388,7 +391,7 @@ namespace NBitcoin ...@@ -388,7 +391,7 @@ namespace NBitcoin
public IDisposable ProtocolVersionScope(ProtocolVersion version) public IDisposable ProtocolVersionScope(ProtocolVersion version)
{ {
var old = this.ProtocolVersion; ProtocolVersion old = this.ProtocolVersion;
return new Scope(() => return new Scope(() =>
{ {
this.ProtocolVersion = version; this.ProtocolVersion = version;
...@@ -419,7 +422,7 @@ namespace NBitcoin ...@@ -419,7 +422,7 @@ namespace NBitcoin
public IDisposable SerializationTypeScope(SerializationType value) public IDisposable SerializationTypeScope(SerializationType value)
{ {
var old = this.Type; SerializationType old = this.Type;
return new Scope(() => return new Scope(() =>
{ {
this.Type = value; this.Type = value;
......
...@@ -23,16 +23,16 @@ namespace NBitcoin ...@@ -23,16 +23,16 @@ namespace NBitcoin
} }
// 20,000 items with fp rate < 0.1% or 10,000 items and <0.0001% // 20,000 items with fp rate < 0.1% or 10,000 items and <0.0001%
const uint MAX_BLOOM_FILTER_SIZE = 36000; // bytes private const uint MAX_BLOOM_FILTER_SIZE = 36000; // bytes
const uint MAX_HASH_FUNCS = 50; private const uint MAX_HASH_FUNCS = 50;
const decimal LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455M; private const decimal LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455M;
const decimal LN2 = 0.6931471805599453094172321214581765680755001343602552M; private const decimal LN2 = 0.6931471805599453094172321214581765680755001343602552M;
byte[] vData; private byte[] vData;
uint nHashFuncs; private uint nHashFuncs;
uint nTweak; private uint nTweak;
byte nFlags; private byte nFlags;
private bool isFull = false; private bool isFull = false;
private bool isEmpty; private bool isEmpty;
...@@ -48,49 +48,50 @@ namespace NBitcoin ...@@ -48,49 +48,50 @@ namespace NBitcoin
// The ideal size for a bloom filter with a given number of elements and false positive rate is: // 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 // - nElements * log(fp rate) / ln(2)^2
// We ignore filter parameters which will create a bloom filter larger than the protocol limits // 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), //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 // 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 // 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 // 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.nTweak = nTweakIn;
this.nFlags = (byte)nFlagsIn; 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. // 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) public void Insert(byte[] vKey)
{ {
if(isFull) if(this.isFull)
return; return;
for(uint i = 0; i < nHashFuncs; i++) for(uint i = 0; i < this.nHashFuncs; i++)
{ {
uint nIndex = Hash(i, vKey); uint nIndex = Hash(i, vKey);
// Sets bit nIndex of vData // 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) public bool Contains(byte[] vKey)
{ {
if(isFull) if(this.isFull)
return true; return true;
if(isEmpty) if(this.isEmpty)
return false; return false;
for(uint i = 0; i < nHashFuncs; i++) for(uint i = 0; i < this.nHashFuncs; i++)
{ {
uint nIndex = Hash(i, vKey); uint nIndex = Hash(i, vKey);
// Checks bit nIndex of vData // 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 false;
} }
return true; return true;
...@@ -125,17 +126,17 @@ namespace NBitcoin ...@@ -125,17 +126,17 @@ namespace NBitcoin
public bool IsWithinSizeConstraints() 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 #region IBitcoinSerializable Members
public void ReadWrite(BitcoinStream stream) public void ReadWrite(BitcoinStream stream)
{ {
stream.ReadWriteAsVarString(ref vData); stream.ReadWriteAsVarString(ref this.vData);
stream.ReadWrite(ref nHashFuncs); stream.ReadWrite(ref this.nHashFuncs);
stream.ReadWrite(ref nTweak); stream.ReadWrite(ref this.nTweak);
stream.ReadWrite(ref nFlags); stream.ReadWrite(ref this.nFlags);
} }
#endregion #endregion
...@@ -146,13 +147,13 @@ namespace NBitcoin ...@@ -146,13 +147,13 @@ namespace NBitcoin
{ {
if(tx == null) if(tx == null)
throw new ArgumentNullException("tx"); throw new ArgumentNullException("tx");
var hash = tx.GetHash(); uint256 hash = tx.GetHash();
bool fFound = false; bool fFound = false;
// Match if the filter contains the hash of tx // Match if the filter contains the hash of tx
// for finding tx when they appear in a block // for finding tx when they appear in a block
if(isFull) if(this.isFull)
return true; return true;
if(isEmpty) if(this.isEmpty)
return false; return false;
if(Contains(hash)) if(Contains(hash))
fFound = true; fFound = true;
...@@ -169,11 +170,11 @@ namespace NBitcoin ...@@ -169,11 +170,11 @@ namespace NBitcoin
if(op.PushData != null && op.PushData.Length != 0 && Contains(op.PushData)) if(op.PushData != null && op.PushData.Length != 0 && Contains(op.PushData))
{ {
fFound = true; 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)); 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 && if(template != null &&
(template.Type == TxOutType.TX_PUBKEY || template.Type == TxOutType.TX_MULTISIG)) (template.Type == TxOutType.TX_PUBKEY || template.Type == TxOutType.TX_MULTISIG))
Insert(new OutPoint(hash, i)); Insert(new OutPoint(hash, i));
......
...@@ -8,7 +8,7 @@ namespace NBitcoin.BuilderExtensions ...@@ -8,7 +8,7 @@ namespace NBitcoin.BuilderExtensions
{ {
public override bool CanCombineScriptSig(Network network, Script scriptPubKey, Script a, Script b) 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) public override bool CanDeduceScriptPubKey(Network network, Script scriptSig)
...@@ -18,31 +18,31 @@ namespace NBitcoin.BuilderExtensions ...@@ -18,31 +18,31 @@ namespace NBitcoin.BuilderExtensions
public override bool CanEstimateScriptSigSize(Network network, Script scriptPubKey) 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) 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) 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: // Combine all the signatures we've got:
var aSigs = PayToMultiSigTemplate.Instance.ExtractScriptSigParameters(network, a); TransactionSignature[] aSigs = PayToMultiSigTemplate.Instance.ExtractScriptSigParameters(network, a);
if(aSigs == null) if(aSigs == null)
return b; return b;
var bSigs = PayToMultiSigTemplate.Instance.ExtractScriptSigParameters(network, b); TransactionSignature[] bSigs = PayToMultiSigTemplate.Instance.ExtractScriptSigParameters(network, b);
if(bSigs == null) if(bSigs == null)
return a; return a;
int sigCount = 0; 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++) for(int i = 0; i < para.PubKeys.Length; i++)
{ {
var aSig = i < aSigs.Length ? aSigs[i] : null; TransactionSignature aSig = i < aSigs.Length ? aSigs[i] : null;
var bSig = i < bSigs.Length ? bSigs[i] : null; TransactionSignature bSig = i < bSigs.Length ? bSigs[i] : null;
var sig = aSig ?? bSig; TransactionSignature sig = aSig ?? bSig;
if(sig != null) if(sig != null)
{ {
sigs[i] = sig; sigs[i] = sig;
...@@ -63,15 +63,15 @@ namespace NBitcoin.BuilderExtensions ...@@ -63,15 +63,15 @@ namespace NBitcoin.BuilderExtensions
public override int EstimateScriptSigSize(Network network, Script scriptPubKey) 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; 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) public override Script GenerateScriptSig(Network network, Script scriptPubKey, IKeyRepository keyRepo, ISigner signer)
{ {
var multiSigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(network, scriptPubKey); PayToMultiSigTemplateParameters multiSigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);
TransactionSignature[] signatures = new TransactionSignature[multiSigParams.PubKeys.Length]; var signatures = new TransactionSignature[multiSigParams.PubKeys.Length];
var keys = Key[] keys =
multiSigParams multiSigParams
.PubKeys .PubKeys
.Select(p => keyRepo.FindKey(p.ScriptPubKey)) .Select(p => keyRepo.FindKey(p.ScriptPubKey))
...@@ -84,7 +84,7 @@ namespace NBitcoin.BuilderExtensions ...@@ -84,7 +84,7 @@ namespace NBitcoin.BuilderExtensions
break; break;
if(keys[i] != null) if(keys[i] != null)
{ {
var sig = signer.Sign(keys[i]); TransactionSignature sig = signer.Sign(keys[i]);
signatures[i] = sig; signatures[i] = sig;
sigCount++; sigCount++;
} }
......
...@@ -4,29 +4,29 @@ ...@@ -4,29 +4,29 @@
{ {
public override bool CanCombineScriptSig(Network network, Script scriptPubKey, Script a, Script b) 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) 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; return para != null && para.PublicKey != null;
} }
public override bool CanEstimateScriptSigSize(Network network, Script scriptPubKey) 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) 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) public override Script CombineScriptSig(Network network, Script scriptPubKey, Script a, Script b)
{ {
var aSig = PayToPubkeyHashTemplate.Instance.ExtractScriptSigParameters(network, a); PayToPubkeyHashScriptSigParameters aSig = PayToPubkeyHashTemplate.Instance.ExtractScriptSigParameters(network, a);
var bSig = PayToPubkeyHashTemplate.Instance.ExtractScriptSigParameters(network, b); PayToPubkeyHashScriptSigParameters bSig = PayToPubkeyHashTemplate.Instance.ExtractScriptSigParameters(network, b);
if(aSig == null) if(aSig == null)
return b; return b;
if(bSig == null) if(bSig == null)
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
public override Script DeduceScriptPubKey(Network network, Script scriptSig) 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; return p2pkh.PublicKey.Hash.ScriptPubKey;
} }
...@@ -50,11 +50,11 @@ ...@@ -50,11 +50,11 @@
public override Script GenerateScriptSig(Network network, Script scriptPubKey, IKeyRepository keyRepo, ISigner signer) public override Script GenerateScriptSig(Network network, Script scriptPubKey, IKeyRepository keyRepo, ISigner signer)
{ {
var parameters = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey); KeyId parameters = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);
var key = keyRepo.FindKey(parameters.ScriptPubKey); Key key = keyRepo.FindKey(parameters.ScriptPubKey);
if(key == null) if(key == null)
return null; return null;
var sig = signer.Sign(key); TransactionSignature sig = signer.Sign(key);
return PayToPubkeyHashTemplate.Instance.GenerateScriptSig(sig, key.PubKey); return PayToPubkeyHashTemplate.Instance.GenerateScriptSig(sig, key.PubKey);
} }
} }
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using NBitcoin.Protocol;
namespace NBitcoin namespace NBitcoin
{ {
public class CachedNoSqlRepository : NoSqlRepository public class CachedNoSqlRepository : NoSqlRepository
{ {
class Raw : IBitcoinSerializable private class Raw : IBitcoinSerializable
{ {
public Raw() public Raw()
{ {
} }
public Raw(byte[] data)
{
var str = new VarString();
str.FromBytes(data);
_Data = str.GetString(true);
}
private byte[] _Data = new byte[0]; private byte[] _Data = new byte[0];
public byte[] Data public byte[] Data
{ {
get get
{ {
return _Data; return this._Data;
} }
} }
#region IBitcoinSerializable Members #region IBitcoinSerializable Members
public void ReadWrite(BitcoinStream stream) public void ReadWrite(BitcoinStream stream)
{ {
stream.ReadWriteAsVarString(ref _Data); stream.ReadWriteAsVarString(ref this._Data);
} }
#endregion #endregion
} }
public CachedNoSqlRepository(NoSqlRepository inner) public CachedNoSqlRepository(NoSqlRepository inner) : base(inner.Network)
{ {
_InnerRepository = inner; this.InnerRepository = inner;
}
private readonly NoSqlRepository _InnerRepository;
public NoSqlRepository InnerRepository
{
get
{
return _InnerRepository;
}
} }
Dictionary<string, byte[]> _Table = new Dictionary<string, byte[]>();
HashSet<string> _Removed = new HashSet<string>(); public NoSqlRepository InnerRepository { get; }
HashSet<string> _Added = new HashSet<string>();
ReaderWriterLock @lock = new ReaderWriterLock(); 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) public override async Task PutBatch(IEnumerable<Tuple<string, IBitcoinSerializable>> values)
{ {
await base.PutBatch(values).ConfigureAwait(false); 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) 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); this._Table.Remove(data.Item1);
_Removed.Add(data.Item1); this._Removed.Add(data.Item1);
_Added.Remove(data.Item1); this._Added.Remove(data.Item1);
} }
else else
{ {
_Table.AddOrReplace(data.Item1, data.Item2); this._Table.AddOrReplace(data.Item1, data.Item2);
_Removed.Remove(data.Item1); this._Removed.Remove(data.Item1);
_Added.Add(data.Item1); this._Added.Add(data.Item1);
} }
} }
} }
...@@ -88,37 +77,23 @@ namespace NBitcoin ...@@ -88,37 +77,23 @@ namespace NBitcoin
{ {
byte[] result = null; byte[] result = null;
bool found; 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); Raw raw = await this.InnerRepository.GetAsync<Raw>(key).ConfigureAwait(false);
if(raw != null) if (raw != null)
{ {
result = raw.Data; result = raw.Data;
using(@lock.LockWrite()) using (this.@lock.LockWrite())
{ {
_Table.AddOrReplace(key, raw.Data); this._Table.AddOrReplace(key, raw.Data);
} }
} }
} }
return result; 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
This diff is collapsed.
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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using NBitcoin.BouncyCastle.Math;
using NBitcoin.DataEncoders;
namespace NBitcoin.Networks 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 ...@@ -34,7 +34,7 @@ namespace NBitcoin.Networks
this.FallbackFee = 60000; this.FallbackFee = 60000;
this.MinRelayTxFee = 10000; this.MinRelayTxFee = 10000;
this..Consensus.SubsidyHalvingInterval = 210000; this.Consensus.SubsidyHalvingInterval = 210000;
this.Consensus.MajorityEnforceBlockUpgrade = 750; this.Consensus.MajorityEnforceBlockUpgrade = 750;
this.Consensus.MajorityRejectBlockOutdated = 950; this.Consensus.MajorityRejectBlockOutdated = 950;
this.Consensus.MajorityWindow = 1000; this.Consensus.MajorityWindow = 1000;
...@@ -51,7 +51,7 @@ namespace NBitcoin.Networks ...@@ -51,7 +51,7 @@ namespace NBitcoin.Networks
this.Consensus.MinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing this.Consensus.MinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
this.Consensus.LastPOWBlock = 12500; this.Consensus.LastPOWBlock = 12500;
this.Consensus.IsProofOfStake = true; 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.ProofOfStakeLimit = new BigInteger(uint256.Parse("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").ToBytes(false));
this.Consensus.ProofOfStakeLimitV2 = new BigInteger(uint256.Parse("000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff").ToBytes(false)); this.Consensus.ProofOfStakeLimitV2 = new BigInteger(uint256.Parse("000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff").ToBytes(false));
this.Consensus.CoinType = 105; this.Consensus.CoinType = 105;
......
...@@ -7,16 +7,16 @@ namespace NBitcoin ...@@ -7,16 +7,16 @@ namespace NBitcoin
{ {
public abstract class NoSqlRepository 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) 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) public void Put(string key, IBitcoinSerializable obj)
...@@ -26,12 +26,13 @@ namespace NBitcoin ...@@ -26,12 +26,13 @@ namespace NBitcoin
public async Task<T> GetAsync<T>(string key) where T : IBitcoinSerializable, new() public async Task<T> GetAsync<T>(string key) where T : IBitcoinSerializable, new()
{ {
var data = await GetBytes(key).ConfigureAwait(false); byte[] data = await GetBytes(key).ConfigureAwait(false);
if(data == null) if (data == null)
return default(T); 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 = Activator.CreateInstance<T>();
obj.ReadWrite(data, network: this.network); obj.ReadWrite(data, consensusFactory: this.Network.Consensus.ConsensusFactory);
return obj; return obj;
} }
...@@ -53,4 +54,4 @@ namespace NBitcoin ...@@ -53,4 +54,4 @@ namespace NBitcoin
return PutBytesBatch(new[] { new Tuple<string, byte[]>(key, data) }); return PutBytesBatch(new[] { new Tuple<string, byte[]>(key, data) });
} }
} }
} }
\ No newline at end of file
#if !NOHTTPCLIENT using System;
using System;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
...@@ -7,14 +6,8 @@ namespace NBitcoin ...@@ -7,14 +6,8 @@ namespace NBitcoin
{ {
public class QBitNinjaTransactionRepository : ITransactionRepository public class QBitNinjaTransactionRepository : ITransactionRepository
{ {
private readonly Uri _BaseUri; public readonly Uri BaseUri;
public Uri BaseUri private readonly Network network;
{
get
{
return _BaseUri;
}
}
/// <summary> /// <summary>
/// Use qbitninja public servers /// Use qbitninja public servers
...@@ -22,38 +15,35 @@ namespace NBitcoin ...@@ -22,38 +15,35 @@ namespace NBitcoin
/// <param name="network"></param> /// <param name="network"></param>
public QBitNinjaTransactionRepository(Network network) public QBitNinjaTransactionRepository(Network network)
{ {
if(network == null) this.network = network ?? throw new ArgumentNullException("network");
throw new ArgumentNullException("network"); this.BaseUri = new Uri("http://" + (network == Network.Main ? "" : "t") + "api.qbit.ninja/");
_BaseUri = new Uri("http://" + (network == Network.Main ? "" : "t") + "api.qbit.ninja/");
} }
public QBitNinjaTransactionRepository(Uri baseUri) public QBitNinjaTransactionRepository(Uri baseUri)
: this(baseUri.AbsoluteUri) : this(baseUri.AbsoluteUri)
{ {
} }
public QBitNinjaTransactionRepository(string baseUri) public QBitNinjaTransactionRepository(string baseUri)
{ {
if(!baseUri.EndsWith("/")) if(!baseUri.EndsWith("/"))
baseUri += "/"; baseUri += "/";
_BaseUri = new Uri(baseUri, UriKind.Absolute);
}
this.BaseUri = new Uri(baseUri, UriKind.Absolute);
}
#region ITransactionRepository Members
public async Task<Transaction> GetAsync(uint256 txId) 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) if(tx.StatusCode == System.Net.HttpStatusCode.NotFound)
return null; return null;
tx.EnsureSuccessStatusCode(); 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 ...@@ -61,8 +51,5 @@ namespace NBitcoin
{ {
return Task.FromResult(false); return Task.FromResult(false);
} }
#endregion
} }
} }
#endif \ No newline at end of file
\ 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; ...@@ -5,8 +5,12 @@ using Newtonsoft.Json.Linq;
namespace NBitcoin.RPC namespace NBitcoin.RPC
{ {
class BlockExplorerFormatter : RawFormatter internal class BlockExplorerFormatter : RawFormatter
{ {
internal BlockExplorerFormatter(Network network) : base(network)
{
}
protected override void BuildTransaction(JObject json, Transaction tx) protected override void BuildTransaction(JObject json, Transaction tx)
{ {
tx.Version = (uint)json.GetValue("ver"); tx.Version = (uint)json.GetValue("ver");
...@@ -14,7 +18,7 @@ namespace NBitcoin.RPC ...@@ -14,7 +18,7 @@ namespace NBitcoin.RPC
var vin = (JArray)json.GetValue("in"); var vin = (JArray)json.GetValue("in");
int vinCount = (int)json.GetValue("vin_sz"); 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 jsonIn = (JObject)vin[i];
var txin = new TxIn(); var txin = new TxIn();
...@@ -25,19 +29,19 @@ namespace NBitcoin.RPC ...@@ -25,19 +29,19 @@ namespace NBitcoin.RPC
txin.PrevOut.N = (uint)prevout.GetValue("n"); txin.PrevOut.N = (uint)prevout.GetValue("n");
var script = (string)jsonIn.GetValue("scriptSig"); string script = (string)jsonIn.GetValue("scriptSig");
if(script != null) if (script != null)
{ {
txin.ScriptSig = new Script(script); txin.ScriptSig = new Script(script);
} }
else else
{ {
var coinbase = (string)jsonIn.GetValue("coinbase"); string coinbase = (string)jsonIn.GetValue("coinbase");
txin.ScriptSig = new Script(Encoders.Hex.DecodeData(coinbase)); txin.ScriptSig = new Script(Encoders.Hex.DecodeData(coinbase));
} }
var seq = jsonIn.GetValue("sequence"); JToken seq = jsonIn.GetValue("sequence");
if(seq != null) if (seq != null)
{ {
txin.Sequence = (uint)seq; txin.Sequence = (uint)seq;
} }
...@@ -45,10 +49,10 @@ namespace NBitcoin.RPC ...@@ -45,10 +49,10 @@ namespace NBitcoin.RPC
var vout = (JArray)json.GetValue("out"); var vout = (JArray)json.GetValue("out");
int voutCount = (int)json.GetValue("vout_sz"); 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 jsonOut = (JObject)vout[i];
var txout = new NBitcoin.TxOut(); var txout = new TxOut();
tx.Outputs.Add(txout); tx.Outputs.Add(txout);
txout.Value = Money.Parse((string)jsonOut.GetValue("value")); txout.Value = Money.Parse((string)jsonOut.GetValue("value"));
...@@ -70,9 +74,9 @@ namespace NBitcoin.RPC ...@@ -70,9 +74,9 @@ namespace NBitcoin.RPC
writer.WritePropertyName("in"); writer.WritePropertyName("in");
writer.WriteStartArray(); 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.WriteStartObject();
writer.WritePropertyName("prev_out"); writer.WritePropertyName("prev_out");
writer.WriteStartObject(); writer.WriteStartObject();
...@@ -80,7 +84,7 @@ namespace NBitcoin.RPC ...@@ -80,7 +84,7 @@ namespace NBitcoin.RPC
WritePropertyValue(writer, "n", txin.PrevOut.N); WritePropertyValue(writer, "n", txin.PrevOut.N);
writer.WriteEndObject(); writer.WriteEndObject();
if(txin.PrevOut.Hash == uint256.Zero) if (txin.PrevOut.Hash == uint256.Zero)
{ {
WritePropertyValue(writer, "coinbase", Encoders.Hex.EncodeData(txin.ScriptSig.ToBytes())); WritePropertyValue(writer, "coinbase", Encoders.Hex.EncodeData(txin.ScriptSig.ToBytes()));
} }
...@@ -88,11 +92,11 @@ namespace NBitcoin.RPC ...@@ -88,11 +92,11 @@ namespace NBitcoin.RPC
{ {
WritePropertyValue(writer, "scriptSig", txin.ScriptSig.ToString()); WritePropertyValue(writer, "scriptSig", txin.ScriptSig.ToString());
} }
if(input.WitScript != WitScript.Empty) if (input.WitScript != WitScript.Empty)
{ {
WritePropertyValue(writer, "witness", input.WitScript.ToString()); WritePropertyValue(writer, "witness", input.WitScript.ToString());
} }
if(txin.Sequence != uint.MaxValue) if (txin.Sequence != uint.MaxValue)
{ {
WritePropertyValue(writer, "sequence", (uint)txin.Sequence); WritePropertyValue(writer, "sequence", (uint)txin.Sequence);
} }
...@@ -102,7 +106,7 @@ namespace NBitcoin.RPC ...@@ -102,7 +106,7 @@ namespace NBitcoin.RPC
writer.WritePropertyName("out"); writer.WritePropertyName("out");
writer.WriteStartArray(); writer.WriteStartArray();
foreach(var txout in tx.Outputs) foreach (TxOut txout in tx.Outputs)
{ {
writer.WriteStartObject(); writer.WriteStartObject();
WritePropertyValue(writer, "value", txout.Value.ToString(false, false)); 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; ...@@ -8,31 +8,6 @@ using Newtonsoft.Json.Linq;
namespace NBitcoin.RPC 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 Category Name Implemented
------------------ --------------------------- ----------------------- ------------------ --------------------------- -----------------------
...@@ -214,8 +189,8 @@ namespace NBitcoin.RPC ...@@ -214,8 +189,8 @@ namespace NBitcoin.RPC
if (options.SubtractFeeFromOutputs != null) if (options.SubtractFeeFromOutputs != null)
{ {
JArray array = new JArray(); var array = new JArray();
foreach(var v in options.SubtractFeeFromOutputs) foreach (int v in options.SubtractFeeFromOutputs)
{ {
array.Add(new JValue(v)); array.Add(new JValue(v));
} }
...@@ -232,7 +207,7 @@ namespace NBitcoin.RPC ...@@ -232,7 +207,7 @@ namespace NBitcoin.RPC
var r = (JObject)response.Result; var r = (JObject)response.Result;
return new FundRawTransactionResponse() 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>()), Fee = Money.Coins(r["fee"].Value<decimal>()),
ChangePos = r["changepos"].Value<int>() ChangePos = r["changepos"].Value<int>()
}; };
...@@ -246,7 +221,7 @@ namespace NBitcoin.RPC ...@@ -246,7 +221,7 @@ namespace NBitcoin.RPC
return tx.ToHex(); return tx.ToHex();
// if there is, do this ACK so that NBitcoin does not change the version number // 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 // getreceivedbyaddress
...@@ -587,7 +562,7 @@ namespace NBitcoin.RPC ...@@ -587,7 +562,7 @@ namespace NBitcoin.RPC
parameters.Add(timeout); parameters.Add(timeout);
await SendCommandAsync(RPCOperations.walletpassphrase, parameters.ToArray()).ConfigureAwait(false); await SendCommandAsync(RPCOperations.walletpassphrase, parameters.ToArray()).ConfigureAwait(false);
} }
/// <summary> /// <summary>
/// Sign a transaction /// Sign a transaction
/// </summary> /// </summary>
...@@ -609,7 +584,7 @@ namespace NBitcoin.RPC ...@@ -609,7 +584,7 @@ namespace NBitcoin.RPC
public async Task<Transaction> SignRawTransactionAsync(Transaction tx) public async Task<Transaction> SignRawTransactionAsync(Transaction tx)
{ {
RPCResponse result = await SendCommandAsync(RPCOperations.signrawtransaction, tx.ToHex()).ConfigureAwait(false); 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; ...@@ -6,13 +6,13 @@ using Newtonsoft.Json.Linq;
namespace NBitcoin.RPC namespace NBitcoin.RPC
{ {
abstract class RawFormatter internal abstract class RawFormatter
{ {
public Network Network { get; set; } 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); protected abstract void BuildTransaction(JObject json, Transaction tx);
...@@ -34,7 +34,7 @@ namespace NBitcoin.RPC ...@@ -34,7 +34,7 @@ namespace NBitcoin.RPC
public Transaction Parse(JObject obj) public Transaction Parse(JObject obj)
{ {
Transaction tx = new Transaction(); var tx = new Transaction();
BuildTransaction(obj, tx); BuildTransaction(obj, tx);
return tx; return tx;
} }
...@@ -44,7 +44,7 @@ namespace NBitcoin.RPC ...@@ -44,7 +44,7 @@ namespace NBitcoin.RPC
writer.WritePropertyName(name); writer.WritePropertyName(name);
writer.WriteValue(value); writer.WriteValue(value);
} }
public string ToString(Transaction transaction) public string ToString(Transaction transaction)
{ {
var strWriter = new StringWriter(); var strWriter = new StringWriter();
...@@ -57,7 +57,7 @@ namespace NBitcoin.RPC ...@@ -57,7 +57,7 @@ namespace NBitcoin.RPC
jsonWriter.Flush(); jsonWriter.Flush();
return strWriter.ToString(); return strWriter.ToString();
} }
} }
} }
#endif #endif
\ No newline at end of file
...@@ -27,44 +27,17 @@ namespace NBitcoin.RPC ...@@ -27,44 +27,17 @@ namespace NBitcoin.RPC
private readonly Uri address; private readonly Uri address;
private readonly Network network; 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> /// <summary>
/// Initializes a new instance of the <see cref="RestClient"/> class. /// Initializes a new instance of the <see cref="RestClient"/> class.
/// </summary> /// </summary>
/// <param name="address">The rest API endpoint</param> /// <param name="address">The rest API endpoint</param>
/// <param name="network">The network to operate with</param> /// <param name="network">The network to operate with</param>
/// <exception cref="System.ArgumentNullException">Null rest API endpoint</exception> /// <exception cref="ArgumentNullException">Null rest API endpoint</exception>
/// <exception cref="System.ArgumentException">Invalid value for RestResponseFormat</exception> /// <exception cref="ArgumentException">Invalid value for RestResponseFormat</exception>
public RestClient(Uri address, Network network) public RestClient(Uri address, Network network)
{ {
if (address == null) this.address = address ?? throw new ArgumentNullException(nameof(address));
throw new ArgumentNullException("address"); this.network = network ?? throw new ArgumentNullException(nameof(network));
if (network == null)
throw new ArgumentNullException("network");
this.address = address;
this.network = network;
} }
/// <summary> /// <summary>
...@@ -72,14 +45,14 @@ namespace NBitcoin.RPC ...@@ -72,14 +45,14 @@ namespace NBitcoin.RPC
/// </summary> /// </summary>
/// <param name="blockId">The block identifier.</param> /// <param name="blockId">The block identifier.</param>
/// <returns>Given a block hash (id) returns the requested block object.</returns> /// <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) public async Task<Block> GetBlockAsync(uint256 blockId)
{ {
if (blockId == null) if (blockId == null)
throw new ArgumentNullException("blockId"); throw new ArgumentNullException("blockId");
byte[] result = await SendRequestAsync("block", RestResponseFormat.Bin, blockId.ToString()).ConfigureAwait(false); byte[] result = await SendRequestAsync("block", RestResponseFormat.Bin, blockId.ToString()).ConfigureAwait(false);
return new Block(result); return Block.Load(result, this.network);
} }
/// <summary> /// <summary>
...@@ -87,7 +60,7 @@ namespace NBitcoin.RPC ...@@ -87,7 +60,7 @@ namespace NBitcoin.RPC
/// </summary> /// </summary>
/// <param name="blockId">The block identifier.</param> /// <param name="blockId">The block identifier.</param>
/// <returns>Given a block hash (id) returns the requested block object.</returns> /// <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) public Block GetBlock(uint256 blockId)
{ {
return GetBlockAsync(blockId).GetAwaiter().GetResult(); return GetBlockAsync(blockId).GetAwaiter().GetResult();
...@@ -105,7 +78,7 @@ namespace NBitcoin.RPC ...@@ -105,7 +78,7 @@ namespace NBitcoin.RPC
throw new ArgumentNullException("txId"); throw new ArgumentNullException("txId");
byte[] result = await SendRequestAsync("tx", RestResponseFormat.Bin, txId.ToString()).ConfigureAwait(false); byte[] result = await SendRequestAsync("tx", RestResponseFormat.Bin, txId.ToString()).ConfigureAwait(false);
return new Transaction(result); return this.network.CreateTransaction(result);
} }
/// <summary> /// <summary>
...@@ -150,8 +123,8 @@ namespace NBitcoin.RPC ...@@ -150,8 +123,8 @@ namespace NBitcoin.RPC
/// <param name="blockId">The initial block identifier.</param> /// <param name="blockId">The initial block identifier.</param>
/// <param name="count">how many headers to get.</param> /// <param name="count">how many headers to get.</param>
/// <returns>Given a block hash (blockId) returns as much block headers as specified.</returns> /// <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="ArgumentNullException">blockId cannot be null</exception>
/// <exception cref="System.ArgumentOutOfRangeException">count must be greater or equal to one.</exception> /// <exception cref="ArgumentOutOfRangeException">count must be greater or equal to one.</exception>
public IEnumerable<BlockHeader> GetBlockHeaders(uint256 blockId, int count) public IEnumerable<BlockHeader> GetBlockHeaders(uint256 blockId, int count)
{ {
return GetBlockHeadersAsync(blockId, count).GetAwaiter().GetResult(); return GetBlockHeadersAsync(blockId, count).GetAwaiter().GetResult();
...@@ -164,7 +137,7 @@ namespace NBitcoin.RPC ...@@ -164,7 +137,7 @@ namespace NBitcoin.RPC
public async Task<ChainInfo> GetChainInfoAsync() public async Task<ChainInfo> GetChainInfoAsync()
{ {
byte[] result = await SendRequestAsync("chaininfo", RestResponseFormat.Json).ConfigureAwait(false); 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 return new ChainInfo
{ {
...@@ -185,7 +158,7 @@ namespace NBitcoin.RPC ...@@ -185,7 +158,7 @@ namespace NBitcoin.RPC
/// <param name="outPoints">The out points identifiers (TxIn-N).</param> /// <param name="outPoints">The out points identifiers (TxIn-N).</param>
/// <param name="checkMempool">if set to <c>true</c> [check mempool].</param> /// <param name="checkMempool">if set to <c>true</c> [check mempool].</param>
/// <returns>The unspent transaction outputs (UTXO) for the given outPoints.</returns> /// <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) public async Task<UTxOutputs> GetUnspentOutputsAsync(IEnumerable<OutPoint> outPoints, bool checkMempool)
{ {
if (outPoints == null) if (outPoints == null)
...@@ -216,11 +189,11 @@ namespace NBitcoin.RPC ...@@ -216,11 +189,11 @@ namespace NBitcoin.RPC
byte[] result = await SendRequestAsync($"gettxout/{txid.ToString()}/{vout.ToString() + (includeMemPool ? "/includemempool" : "")}", byte[] result = await SendRequestAsync($"gettxout/{txid.ToString()}/{vout.ToString() + (includeMemPool ? "/includemempool" : "")}",
RestResponseFormat.Json).ConfigureAwait(false); 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)) if (string.IsNullOrEmpty(responseString))
return null; return null;
var objectResult = JObject.Parse(responseString); JObject objectResult = JObject.Parse(responseString);
return new UnspentTransaction(objectResult); return new UnspentTransaction(objectResult);
} }
...@@ -232,23 +205,22 @@ namespace NBitcoin.RPC ...@@ -232,23 +205,22 @@ namespace NBitcoin.RPC
using (WebResponse response = await GetWebResponseAsync(request).ConfigureAwait(false)) using (WebResponse response = await GetWebResponseAsync(request).ConfigureAwait(false))
{ {
Stream stream = response.GetResponseStream(); Stream stream = response.GetResponseStream();
var bytesToRead = (int)response.ContentLength; int bytesToRead = (int)response.ContentLength;
byte[] buffer = await stream.ReadBytesAsync(bytesToRead).ConfigureAwait(false); byte[] buffer = await stream.ReadBytesAsync(bytesToRead).ConfigureAwait(false);
return buffer; return buffer;
} }
} }
#region Private methods
private WebRequest BuildHttpRequest(string resource, RestResponseFormat format, params string[] parms) 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); var uriBuilder = new UriBuilder(this.address);
uriBuilder.Path = "rest/" + resource + (hasParams ? "/" : "") + string.Join("/", parms) + "." + format.ToString().ToLowerInvariant(); uriBuilder.Path = "rest/" + resource + (hasParams ? "/" : "") + string.Join("/", parms) + "." + format.ToString().ToLowerInvariant();
HttpWebRequest request = WebRequest.CreateHttp(uriBuilder.Uri); HttpWebRequest request = WebRequest.CreateHttp(uriBuilder.Uri);
request.Method = "GET"; request.Method = "GET";
#if !(PORTABLE || NETCORE) #if !NETCORE
request.KeepAlive = false; request.KeepAlive = false;
#endif #endif
return request; return request;
...@@ -263,10 +235,8 @@ namespace NBitcoin.RPC ...@@ -263,10 +235,8 @@ namespace NBitcoin.RPC
{ {
response = await request.GetResponseAsync().ConfigureAwait(false); 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 // Even if the request "failed" we need to continue reading the response from the router
response = ex.Response as HttpWebResponse; response = ex.Response as HttpWebResponse;
...@@ -279,14 +249,13 @@ namespace NBitcoin.RPC ...@@ -279,14 +249,13 @@ namespace NBitcoin.RPC
if (exception != null) if (exception != null)
{ {
Stream stream = response.GetResponseStream(); Stream stream = response.GetResponseStream();
var bytesToRead = (int)response.ContentLength; int bytesToRead = (int)response.ContentLength;
byte[] buffer = await stream.ReadBytesAsync(bytesToRead).ConfigureAwait(false); byte[] buffer = await stream.ReadBytesAsync(bytesToRead).ConfigureAwait(false);
response.Dispose(); response.Dispose();
throw new RestApiException(Encoding.UTF8.GetString(buffer, 0, buffer.Length - 2), exception); throw new RestApiException(Encoding.UTF8.GetString(buffer, 0, buffer.Length - 2), exception);
} }
return response; return response;
} }
#endregion
} }
public class RestApiException : Exception public class RestApiException : Exception
......
...@@ -8,13 +8,10 @@ using Newtonsoft.Json.Linq; ...@@ -8,13 +8,10 @@ using Newtonsoft.Json.Linq;
namespace NBitcoin.RPC namespace NBitcoin.RPC
{ {
class SatoshiFormatter : RawFormatter internal class SatoshiFormatter : RawFormatter
{ {
private readonly Network network; public SatoshiFormatter(Network network) : base(network)
public SatoshiFormatter(Network network)
{ {
this.network = network;
} }
protected override void BuildTransaction(JObject json, Transaction tx) protected override void BuildTransaction(JObject json, Transaction tx)
...@@ -23,14 +20,14 @@ namespace NBitcoin.RPC ...@@ -23,14 +20,14 @@ namespace NBitcoin.RPC
tx.LockTime = (uint)json.GetValue("locktime"); tx.LockTime = (uint)json.GetValue("locktime");
var vin = (JArray)json.GetValue("vin"); 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 jsonIn = (JObject)vin[i];
var txin = new TxIn(); var txin = new TxIn();
tx.Inputs.Add(txin); tx.Inputs.Add(txin);
var script = (JObject)jsonIn.GetValue("scriptSig"); var script = (JObject)jsonIn.GetValue("scriptSig");
if(script != null) if (script != null)
{ {
txin.ScriptSig = new Script(Encoders.Hex.DecodeData((string)script.GetValue("hex"))); txin.ScriptSig = new Script(Encoders.Hex.DecodeData((string)script.GetValue("hex")));
txin.PrevOut.Hash = uint256.Parse((string)jsonIn.GetValue("txid")); txin.PrevOut.Hash = uint256.Parse((string)jsonIn.GetValue("txid"));
...@@ -38,7 +35,7 @@ namespace NBitcoin.RPC ...@@ -38,7 +35,7 @@ namespace NBitcoin.RPC
} }
else else
{ {
var coinbase = (string)jsonIn.GetValue("coinbase"); string coinbase = (string)jsonIn.GetValue("coinbase");
txin.ScriptSig = new Script(Encoders.Hex.DecodeData(coinbase)); txin.ScriptSig = new Script(Encoders.Hex.DecodeData(coinbase));
} }
...@@ -47,14 +44,14 @@ namespace NBitcoin.RPC ...@@ -47,14 +44,14 @@ namespace NBitcoin.RPC
} }
var vout = (JArray)json.GetValue("vout"); 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 jsonOut = (JObject)vout[i];
var txout = new TxOut(); var txout = new TxOut();
tx.Outputs.Add(txout); tx.Outputs.Add(txout);
var btc = (decimal)jsonOut.GetValue("value"); decimal btc = (decimal)jsonOut.GetValue("value");
var satoshis = btc * Money.COIN; decimal satoshis = btc * Money.COIN;
txout.Value = new Money((long)(satoshis)); txout.Value = new Money((long)(satoshis));
var script = (JObject)jsonOut.GetValue("scriptPubKey"); var script = (JObject)jsonOut.GetValue("scriptPubKey");
...@@ -70,11 +67,11 @@ namespace NBitcoin.RPC ...@@ -70,11 +67,11 @@ namespace NBitcoin.RPC
writer.WritePropertyName("vin"); writer.WritePropertyName("vin");
writer.WriteStartArray(); writer.WriteStartArray();
foreach(var txin in tx.Inputs) foreach (TxIn txin in tx.Inputs)
{ {
writer.WriteStartObject(); writer.WriteStartObject();
if(txin.PrevOut.Hash == uint256.Zero) if (txin.PrevOut.Hash == uint256.Zero)
{ {
WritePropertyValue(writer, "coinbase", Encoders.Hex.EncodeData(txin.ScriptSig.ToBytes())); WritePropertyValue(writer, "coinbase", Encoders.Hex.EncodeData(txin.ScriptSig.ToBytes()));
} }
...@@ -99,7 +96,7 @@ namespace NBitcoin.RPC ...@@ -99,7 +96,7 @@ namespace NBitcoin.RPC
writer.WriteStartArray(); writer.WriteStartArray();
int i = 0; int i = 0;
foreach(var txout in tx.Outputs) foreach (TxOut txout in tx.Outputs)
{ {
writer.WriteStartObject(); writer.WriteStartObject();
writer.WritePropertyName("value"); writer.WritePropertyName("value");
...@@ -112,28 +109,28 @@ namespace NBitcoin.RPC ...@@ -112,28 +109,28 @@ namespace NBitcoin.RPC
WritePropertyValue(writer, "asm", txout.ScriptPubKey.ToString()); WritePropertyValue(writer, "asm", txout.ScriptPubKey.ToString());
WritePropertyValue(writer, "hex", Encoders.Hex.EncodeData(txout.ScriptPubKey.ToBytes())); WritePropertyValue(writer, "hex", Encoders.Hex.EncodeData(txout.ScriptPubKey.ToBytes()));
var destinations = new List<TxDestination>() { txout.ScriptPubKey.GetDestination(this.network) }; var destinations = new List<TxDestination>() { txout.ScriptPubKey.GetDestination(this.Network) };
if(destinations[0] == null) if (destinations[0] == null)
{ {
destinations = txout.ScriptPubKey.GetDestinationPublicKeys(this.network) destinations = txout.ScriptPubKey.GetDestinationPublicKeys(this.Network)
.Select(p => p.Hash) .Select(p => p.Hash)
.ToList<TxDestination>(); .ToList<TxDestination>();
} }
if(destinations.Count == 1) if (destinations.Count == 1)
{ {
WritePropertyValue(writer, "reqSigs", 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.WritePropertyName("addresses");
writer.WriteStartArray(); writer.WriteStartArray();
writer.WriteValue(destinations[0].GetAddress(Network).ToString()); writer.WriteValue(destinations[0].GetAddress(this.Network).ToString());
writer.WriteEndArray(); writer.WriteEndArray();
} }
else else
{ {
var multi = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(this.network, txout.ScriptPubKey); PayToMultiSigTemplateParameters multi = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(txout.ScriptPubKey);
if (multi != null) if (multi != null)
WritePropertyValue(writer, "reqSigs", multi.SignatureCount); 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) if (multi != null)
{ {
writer.WritePropertyName("addresses"); writer.WritePropertyName("addresses");
...@@ -155,20 +152,20 @@ namespace NBitcoin.RPC ...@@ -155,20 +152,20 @@ namespace NBitcoin.RPC
private string ValueFromAmount(Money money) private string ValueFromAmount(Money money)
{ {
var satoshis = (decimal)money.Satoshi; decimal satoshis = (decimal)money.Satoshi;
var btc = satoshis / Money.COIN; decimal btc = satoshis / Money.COIN;
//return btc.ToString("0.###E+00", CultureInfo.InvariantCulture); //return btc.ToString("0.###E+00", CultureInfo.InvariantCulture);
var result = ((double)btc).ToString(CultureInfo.InvariantCulture); string result = ((double)btc).ToString(CultureInfo.InvariantCulture);
if(!result.ToCharArray().Contains('.')) if (!result.ToCharArray().Contains('.'))
result = result + ".0"; result = result + ".0";
return result; return result;
} }
private string GetScriptType(ScriptTemplate template) private string GetScriptType(ScriptTemplate template)
{ {
if(template == null) if (template == null)
return "nonstandard"; return "nonstandard";
switch(template.Type) switch (template.Type)
{ {
case TxOutType.TX_PUBKEY: case TxOutType.TX_PUBKEY:
return "pubkey"; return "pubkey";
......
This diff is collapsed.
...@@ -4,10 +4,9 @@ using NBitcoin.Policy; ...@@ -4,10 +4,9 @@ using NBitcoin.Policy;
namespace NBitcoin namespace NBitcoin
{ {
public static class StandardScripts public static class StandardScripts
{ {
static readonly ScriptTemplate[] _StandardTemplates = new ScriptTemplate[] private static readonly ScriptTemplate[] _StandardTemplates = new ScriptTemplate[]
{ {
PayToPubkeyHashTemplate.Instance, PayToPubkeyHashTemplate.Instance,
PayToPubkeyTemplate.Instance, PayToPubkeyTemplate.Instance,
...@@ -17,10 +16,8 @@ namespace NBitcoin ...@@ -17,10 +16,8 @@ namespace NBitcoin
PayToWitTemplate.Instance 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; return new StandardTransactionPolicy(network).Check(tx, null).Length == 0;
} }
...@@ -29,25 +26,25 @@ namespace NBitcoin ...@@ -29,25 +26,25 @@ namespace NBitcoin
return tx.Outputs.All(vout => IsStandardScriptPubKey(network, vout.ScriptPubKey)); 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) 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) private static bool IsStandardScriptSig(Network network, Script scriptSig, Script scriptPubKey)
{ {
var template = GetTemplateFromScriptPubKey(network, scriptPubKey); ScriptTemplate template = GetTemplateFromScriptPubKey(scriptPubKey);
if(template == null) if(template == null)
return false; return false;
return template.CheckScriptSig(network, scriptSig, scriptPubKey); return template.CheckScriptSig(network, scriptSig, scriptPubKey);
} }
//
// Check transaction inputs, and make sure any // Check transaction inputs, and make sure any
// pay-to-script-hash transactions are evaluating IsStandard scripts // pay-to-script-hash transactions are evaluating IsStandard scripts
// //
...@@ -57,13 +54,12 @@ namespace NBitcoin ...@@ -57,13 +54,12 @@ namespace NBitcoin
// script can be anything; an attacker could use a very // script can be anything; an attacker could use a very
// expensive-to-check-upon-redemption script like: // expensive-to-check-upon-redemption script like:
// DUP CHECKSIG DROP ... repeated 100 times... OP_1 // DUP CHECKSIG DROP ... repeated 100 times... OP_1
//
public static bool AreInputsStandard(Network network, Transaction tx, CoinsView coinsView) public static bool AreInputsStandard(Network network, Transaction tx, CoinsView coinsView)
{ {
if(tx.IsCoinBase) if(tx.IsCoinBase)
return true; // Coinbases don't use vin normally 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); TxOut prev = coinsView.GetOutputFor(input);
if(prev == null) if(prev == null)
...@@ -75,4 +71,4 @@ namespace NBitcoin ...@@ -75,4 +71,4 @@ namespace NBitcoin
return true; return true;
} }
} }
} }
\ No newline at end of file
...@@ -16,9 +16,10 @@ namespace NBitcoin.Stealth ...@@ -16,9 +16,10 @@ namespace NBitcoin.Stealth
} }
throw new ArgumentException("No nonce can satisfy the given bitfield, use another ephemKey"); throw new ArgumentException("No nonce can satisfy the given bitfield, use another ephemKey");
} }
public static StealthMetadata TryParse(Script metadata) public static StealthMetadata TryParse(Script metadata)
{ {
StealthMetadata result = new StealthMetadata(); var result = new StealthMetadata();
try try
{ {
if(!Fill(result, metadata)) if(!Fill(result, metadata))
...@@ -30,9 +31,11 @@ namespace NBitcoin.Stealth ...@@ -30,9 +31,11 @@ namespace NBitcoin.Stealth
} }
return result; return result;
} }
private StealthMetadata() private StealthMetadata()
{ {
} }
public StealthMetadata(Script metadata) public StealthMetadata(Script metadata)
{ {
if(!Fill(this, metadata)) if(!Fill(this, metadata))
...@@ -43,19 +46,20 @@ namespace NBitcoin.Stealth ...@@ -43,19 +46,20 @@ namespace NBitcoin.Stealth
{ {
var data = new MemoryStream(); var data = new MemoryStream();
data.WriteByte(6); data.WriteByte(6);
var b = Utils.ToBytes(nonce, true); byte[] b = Utils.ToBytes(nonce, true);
data.Write(b, 0, b.Length); data.Write(b, 0, b.Length);
data.Write(ephemKey.PubKey.Compress().ToBytes(), 0, 33); data.Write(ephemKey.PubKey.Compress().ToBytes(), 0, 33);
Fill(this, new Script(OpcodeType.OP_RETURN, Op.GetPushOp(data.ToArray()))); 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) private static bool Fill(StealthMetadata output, Script metadata)
{ {
var datas = _Template.ExtractScriptPubKeyParameters(Network.Main, metadata); byte[][] datas = _Template.ExtractScriptPubKeyParameters(metadata);
if(datas == null) if(datas == null)
return false; return false;
foreach(var data in datas) foreach(byte[] data in datas)
{ {
if(Fill(output, metadata, data)) if(Fill(output, metadata, data))
return true; return true;
...@@ -67,7 +71,7 @@ namespace NBitcoin.Stealth ...@@ -67,7 +71,7 @@ namespace NBitcoin.Stealth
{ {
if(data == null || data.Length != 1 + 4 + 33) if(data == null || data.Length != 1 + 4 + 33)
return false; return false;
MemoryStream ms = new MemoryStream(data); var ms = new MemoryStream(data);
output.Version = ms.ReadByte(); output.Version = ms.ReadByte();
if(output.Version != 6) if(output.Version != 6)
return false; return false;
......
...@@ -11,7 +11,7 @@ namespace NBitcoin.Stealth ...@@ -11,7 +11,7 @@ namespace NBitcoin.Stealth
{ {
get get
{ {
return _Payment; return this._Payment;
} }
} }
private readonly KeyId _ID; private readonly KeyId _ID;
...@@ -19,18 +19,18 @@ namespace NBitcoin.Stealth ...@@ -19,18 +19,18 @@ namespace NBitcoin.Stealth
{ {
get get
{ {
return _ID; return this._ID;
} }
} }
public StealthSpendKey(KeyId id, StealthPayment payment) public StealthSpendKey(KeyId id, StealthPayment payment)
{ {
_ID = id; this._ID = id;
_Payment = payment; this._Payment = payment;
} }
public BitcoinAddress GetAddress(Network network) public BitcoinAddress GetAddress(Network network)
{ {
return new BitcoinPubKeyAddress(ID, network); return new BitcoinPubKeyAddress(this.ID, network);
} }
} }
...@@ -38,13 +38,13 @@ namespace NBitcoin.Stealth ...@@ -38,13 +38,13 @@ namespace NBitcoin.Stealth
{ {
public StealthPayment(BitcoinStealthAddress address, Key ephemKey, StealthMetadata metadata) public StealthPayment(BitcoinStealthAddress address, Key ephemKey, StealthMetadata metadata)
{ {
Metadata = metadata; this.Metadata = metadata;
ScriptPubKey = CreatePaymentScript(address.SignatureCount, address.SpendPubKeys, ephemKey, address.ScanPubKey); this.ScriptPubKey = CreatePaymentScript(address.SignatureCount, address.SpendPubKeys, ephemKey, address.ScanPubKey);
if(address.SignatureCount > 1) if(address.SignatureCount > 1)
{ {
Redeem = ScriptPubKey; this.Redeem = this.ScriptPubKey;
ScriptPubKey = ScriptPubKey.Hash.ScriptPubKey; this.ScriptPubKey = this.ScriptPubKey.Hash.ScriptPubKey;
} }
SetStealthKeys(); SetStealthKeys();
} }
...@@ -71,17 +71,16 @@ namespace NBitcoin.Stealth ...@@ -71,17 +71,16 @@ namespace NBitcoin.Stealth
return CreatePaymentScript(address.SignatureCount, address.SpendPubKeys.Select(p => p.UncoverReceiver(scan, ephemKey)).ToArray()); return CreatePaymentScript(address.SignatureCount, address.SpendPubKeys.Select(p => p.UncoverReceiver(scan, ephemKey)).ToArray());
} }
public static KeyId[] ExtractKeyIDs(Script script) public static KeyId[] ExtractKeyIDs(Script script)
{ {
var keyId = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(script); KeyId keyId = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(script);
if(keyId != null) if(keyId != null)
{ {
return new[] { keyId }; return new[] { keyId };
} }
else else
{ {
var para = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(Network.Main, script); PayToMultiSigTemplateParameters para = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(script);
if(para == null) if(para == null)
throw new ArgumentException("Invalid stealth spendable output script", "spendable"); throw new ArgumentException("Invalid stealth spendable output script", "spendable");
return para.PubKeys.Select(k => k.Hash).ToArray(); return para.PubKeys.Select(k => k.Hash).ToArray();
...@@ -93,22 +92,23 @@ namespace NBitcoin.Stealth ...@@ -93,22 +92,23 @@ namespace NBitcoin.Stealth
get; get;
private set; private set;
} }
public BitcoinAddress[] GetAddresses(Network network) 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) public StealthPayment(Script scriptPubKey, Script redeem, StealthMetadata metadata)
{ {
Metadata = metadata; this.Metadata = metadata;
ScriptPubKey = scriptPubKey; this.ScriptPubKey = scriptPubKey;
Redeem = redeem; this.Redeem = redeem;
SetStealthKeys(); SetStealthKeys();
} }
private void 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 ...@@ -134,20 +134,20 @@ namespace NBitcoin.Stealth
throw new ArgumentNullException("transaction"); throw new ArgumentNullException("transaction");
if(value == null) if(value == null)
throw new ArgumentNullException("value"); throw new ArgumentNullException("value");
transaction.Outputs.Add(new TxOut(0, Metadata.Script)); transaction.Outputs.Add(new TxOut(0, this.Metadata.Script));
transaction.Outputs.Add(new TxOut(value, ScriptPubKey)); transaction.Outputs.Add(new TxOut(value, this.ScriptPubKey));
} }
public static StealthPayment[] GetPayments(Transaction transaction, BitcoinStealthAddress address, Key scan) 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++) 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))) if(metadata != null && (address == null || address.Prefix.Match(metadata.BitField)))
{ {
var scriptPubKey = transaction.Outputs[i + 1].ScriptPubKey; Script scriptPubKey = transaction.Outputs[i + 1].ScriptPubKey;
var scriptId = PayToScriptHashTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey); ScriptId scriptId = PayToScriptHashTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);
Script expectedScriptPubKey = address == null ? scriptPubKey : null; Script expectedScriptPubKey = address == null ? scriptPubKey : null;
Script redeem = null; Script redeem = null;
......
This diff is collapsed.
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