Commit 856a95b1 authored by Sergei Zubov's avatar Sergei Zubov

Add NBitcoin tests

parent 9c1440c9
using System;
using NBitcoin.BouncyCastle.Math;
using NBitcoin.DataEncoders;
using Xunit;
namespace NBitcoin.Tests
{
public class DeStreamNetworkTests
{
[Fact]
[Trait("Category", "DeStream")]
public void DeStreamMainIsInitializedCorrectly()
{
Network network = Network.DeStreamMain;
Assert.Equal(2, network.Checkpoints.Count);
Assert.Equal(2, network.DNSSeeds.Count);
Assert.Equal(2, network.SeedNodes.Count);
Assert.Equal("DeStreamMain", network.Name);
Assert.Equal(Network.DeStreamRootFolderName, network.RootFolderName);
Assert.Equal(Network.DeStreamDefaultConfigFilename, network.DefaultConfigFilename);
Assert.Equal(0x10FEFE10.ToString(), network.Magic.ToString());
Assert.Equal(56833, network.DefaultPort);
Assert.Equal(56832, network.RPCPort);
Assert.Equal(Network.DeStreamMaxTimeOffsetSeconds, network.MaxTimeOffsetSeconds);
Assert.Equal(Network.DeStreamDefaultMaxTipAgeInSeconds, network.MaxTipAge);
Assert.Equal(10000, network.MinTxFee);
Assert.Equal(60000, network.FallbackFee);
Assert.Equal(10000, network.MinRelayTxFee);
Assert.Equal("DST", network.CoinTicker);
Assert.Equal(2, network.Bech32Encoders.Length);
Assert.Equal(new Bech32Encoder("bc").ToString(),
network.Bech32Encoders[(int) Bech32Type.WITNESS_PUBKEY_ADDRESS].ToString());
Assert.Equal(new Bech32Encoder("bc").ToString(),
network.Bech32Encoders[(int) Bech32Type.WITNESS_SCRIPT_ADDRESS].ToString());
Assert.Equal(12, network.Base58Prefixes.Length);
Assert.Equal(new byte[] {30}, network.Base58Prefixes[(int) Base58Type.PUBKEY_ADDRESS]);
Assert.Equal(new byte[] {90}, network.Base58Prefixes[(int) Base58Type.SCRIPT_ADDRESS]);
Assert.Equal(new byte[] {30 + 90}, network.Base58Prefixes[(int) Base58Type.SECRET_KEY]);
Assert.Equal(new byte[] {0x01, 0x42}, network.Base58Prefixes[(int) Base58Type.ENCRYPTED_SECRET_KEY_NO_EC]);
Assert.Equal(new byte[] {0x01, 0x43}, network.Base58Prefixes[(int) Base58Type.ENCRYPTED_SECRET_KEY_EC]);
Assert.Equal(new byte[] {0x04, 0x88, 0xB2, 0x1E}, network.Base58Prefixes[(int) Base58Type.EXT_PUBLIC_KEY]);
Assert.Equal(new byte[] {0x04, 0x88, 0xAD, 0xE4}, network.Base58Prefixes[(int) Base58Type.EXT_SECRET_KEY]);
Assert.Equal(new byte[] {0x2C, 0xE9, 0xB3, 0xE1, 0xFF, 0x39, 0xE2},
network.Base58Prefixes[(int) Base58Type.PASSPHRASE_CODE]);
Assert.Equal(new byte[] {0x64, 0x3B, 0xF6, 0xA8, 0x9A},
network.Base58Prefixes[(int) Base58Type.CONFIRMATION_CODE]);
Assert.Equal(new byte[] {0x2a}, network.Base58Prefixes[(int) Base58Type.STEALTH_ADDRESS]);
Assert.Equal(new byte[] {23}, network.Base58Prefixes[(int) Base58Type.ASSET_ID]);
Assert.Equal(new byte[] {0x13}, network.Base58Prefixes[(int) Base58Type.COLORED_ADDRESS]);
Assert.Equal(210000, network.Consensus.SubsidyHalvingInterval);
Assert.Equal(750, network.Consensus.MajorityEnforceBlockUpgrade);
Assert.Equal(950, network.Consensus.MajorityRejectBlockOutdated);
Assert.Equal(1000, network.Consensus.MajorityWindow);
Assert.Equal(0, network.Consensus.BuriedDeployments[BuriedDeployments.BIP34]);
Assert.Equal(0, network.Consensus.BuriedDeployments[BuriedDeployments.BIP65]);
Assert.Equal(0, network.Consensus.BuriedDeployments[BuriedDeployments.BIP66]);
Assert.Equal(new uint256("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8"),
network.Consensus.BIP34Hash);
Assert.Equal(new Target(new uint256("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")),
network.Consensus.PowLimit);
Assert.Null(network.Consensus.MinimumChainWork);
Assert.Equal(TimeSpan.FromSeconds(14 * 24 * 60 * 60), network.Consensus.PowTargetTimespan);
Assert.Equal(TimeSpan.FromSeconds(10 * 60), network.Consensus.PowTargetSpacing);
Assert.False(network.Consensus.PowAllowMinDifficultyBlocks);
Assert.False(network.Consensus.PowNoRetargeting);
Assert.Equal(1916, network.Consensus.RuleChangeActivationThreshold);
Assert.Equal(2016, network.Consensus.MinerConfirmationWindow);
Assert.Null(network.Consensus.BIP9Deployments[BIP9Deployments.TestDummy]);
Assert.Null(network.Consensus.BIP9Deployments[BIP9Deployments.CSV]);
Assert.Null(network.Consensus.BIP9Deployments[BIP9Deployments.Segwit]);
Assert.Equal(1000, network.Consensus.LastPOWBlock);
Assert.True(network.Consensus.IsProofOfStake);
Assert.Equal(3564, network.Consensus.CoinType);
Assert.Equal(
new BigInteger(uint256.Parse("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
.ToBytes(false)), network.Consensus.ProofOfStakeLimit);
Assert.Equal(
new BigInteger(uint256.Parse("000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff")
.ToBytes(false)), network.Consensus.ProofOfStakeLimitV2);
Assert.Equal(new uint256("0x55a8205ae4bbf18f4d238c43f43005bd66e0b1f679b39e2c5c62cf6903693a5e"),
network.Consensus.DefaultAssumeValid);
Assert.Equal(50, network.Consensus.CoinbaseMaturity);
Assert.Null(network.Consensus.PremineReward);
Assert.Equal(0, network.Consensus.PremineHeight);
Assert.Equal(Money.Zero, network.Consensus.ProofOfWorkReward);
Assert.Equal(Money.Zero, network.Consensus.ProofOfStakeReward);
Assert.Equal((uint) 500, network.Consensus.MaxReorgLength);
Assert.Equal(long.MaxValue, network.Consensus.MaxMoney);
Block genesis = network.GetGenesis();
Assert.Equal(uint256.Parse("95dfb30e229e18197a812ece5d8d6c03efc9b9b65a9122a73f17d99613841b1b"),
genesis.GetHash());
Assert.Equal(uint256.Parse("6598d7cc968eae6d6e66e7ac88707f5e0948b816dc8ba52433d7edc1a1f2c6a3"),
genesis.Header.HashMerkleRoot);
}
}
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.1</RuntimeFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;DEBUG;NETCORE;</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE;RELEASE;NETCORE;</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Remove="addrman_tests.cs" />
<Compile Remove="pos_addrman_tests.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NBitcoin\NBitcoin.csproj" />
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
<ItemGroup>
<None Update="data\.cookie">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
......@@ -232,5 +224,4 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
</Project>
\ No newline at end of file
......@@ -9,14 +9,14 @@ namespace NBitcoin
/// The name of the root folder containing the different Stratis blockchains (StratisMain, StratisTest,
/// StratisRegTest).
/// </summary>
protected const string DeStreamRootFolderName = "destream";
protected internal const string DeStreamRootFolderName = "destream";
/// <summary> The default name used for the Stratis configuration file. </summary>
protected const string DeStreamDefaultConfigFilename = "destream.conf";
protected internal const string DeStreamDefaultConfigFilename = "destream.conf";
protected const int DeStreamMaxTimeOffsetSeconds = 25 * 60;
protected internal const int DeStreamMaxTimeOffsetSeconds = 25 * 60;
protected const int DeStreamDefaultMaxTipAgeInSeconds = 2 * 60 * 60;
protected internal const int DeStreamDefaultMaxTipAgeInSeconds = 2 * 60 * 60;
public const string WalletAddressDeStreamMain = "TPPL2wmtxGzP8U6hQsGkRA9yCMsazB33ft";
......
......@@ -23,16 +23,16 @@ namespace NBitcoin
{
IEnumerable<ICoin> result = base.BuildTransaction(ctx, group, builders, coins, zero);
if (ctx.Transaction.Inputs.Any(p => p.PrevOut.Hash == uint256.Zero))
return result;
// To secure that fee is charged from spending coins and not from change,
// we add input with uint256.Zero hash that points to output with change
int changeIndex = ctx.Transaction.Outputs.FindIndex(p =>
p.ScriptPubKey == group.ChangeScript[(int) ctx.ChangeType]);
if (changeIndex == -1) return result;
if (ctx.Transaction.Inputs.Any(p => p.PrevOut.Hash == uint256.Zero && p.PrevOut.N == changeIndex))
return result;
var outPoint = new OutPoint
{
Hash = uint256.Zero,
......@@ -44,10 +44,69 @@ namespace NBitcoin
PrevOut = outPoint
});
group.Coins.Add(outPoint, new Coin(uint256.Zero, outPoint.N,
Money.Zero, @group.ChangeScript[(int) ctx.ChangeType]));
group.Coins.TryAdd(outPoint, new Coin(uint256.Zero, outPoint.N,
Money.Zero, group.ChangeScript[(int) ctx.ChangeType]));
return result;
}
/// <inheritdoc />
public override TransactionBuilder CoverTheRest()
{
if (this._CompletedTransaction == null)
throw new InvalidOperationException(
"A partially built transaction should be specified by calling ContinueToBuild");
Money spent = this._CompletedTransaction.Inputs.AsIndexedInputs().RemoveChangePointer().Select(txin =>
{
ICoin c = this.FindCoin(txin.PrevOut);
if (c == null)
throw this.CoinNotFound(txin);
return c as Coin;
})
.Where(c => c != null)
.Select(c => c.Amount)
.Sum();
Money toComplete = this._CompletedTransaction.TotalOut - spent;
this.CurrentGroup.Builders.Add(ctx => toComplete < Money.Zero ? Money.Zero : toComplete);
return this;
}
/// <inheritdoc />
public override bool Verify(Transaction tx, Money expectedFees, out TransactionPolicyError[] errors)
{
if (tx == null)
throw new ArgumentNullException(nameof(tx));
ICoin[] coins = tx.Inputs.Select(i => this.FindCoin(i.PrevOut)).Where(c => c != null).ToArray();
var exceptions = new List<TransactionPolicyError>();
TransactionPolicyError[] policyErrors = DeStreamMinerTransactionPolicy.Instance.Check(tx, coins);
exceptions.AddRange(policyErrors);
policyErrors = this.StandardTransactionPolicy.Check(tx, coins);
exceptions.AddRange(policyErrors);
if (expectedFees != null)
{
Money fees = tx.GetFee(coins);
if (fees != null)
{
Money margin = Money.Zero;
if (this.DustPrevention)
margin = this.GetDust() * 2;
if (!fees.Almost(expectedFees, margin))
{
exceptions.Add(new NotEnoughFundsPolicyError("Fees different than expected",
expectedFees - fees));
}
}
}
errors = exceptions.ToArray();
return errors.Length == 0;
}
}
}
\ No newline at end of file
......@@ -154,7 +154,11 @@ namespace NBitcoin.Networks
{
{
0, new CheckpointInfo(
new uint256("0x95dfb30e229e18197a812ece5d8d6c03efc9b9b65a9122a73f17d99613841b1b"),
new uint256("0x95dfb30e229e18197a812ece5d8d6c03efc9b9b65a9122a73f17d99613841b1b"))
},
{
1,
new CheckpointInfo(
new uint256("0x0000000000000000000000000000000000000000000000000000000000000000"))
}
};
......
......@@ -156,6 +156,7 @@ namespace NBitcoin.OpenAsset
frame.Transaction = frame.Transaction ?? await repo.Transactions.GetAsync(frame.TransactionId).ConfigureAwait(false);
if(frame.Transaction == null)
throw new TransactionNotFoundException("Transaction " + frame.TransactionId + " not found in transaction repository", frame.TransactionId);
int skipped;
if(frame.PreviousTransactions == null)
{
if(frame.Transaction.IsCoinBase ||
......@@ -165,14 +166,14 @@ namespace NBitcoin.OpenAsset
coloreds.Push(new ColoredTransaction());
continue;
}
frame.PreviousTransactions = new ColoredTransaction[frame.Transaction.Inputs.Count];
frame.PreviousTransactions = new ColoredTransaction[frame.Transaction.Inputs.RemoveChangePointer().Count()];
await BulkLoadIfCached(frame.Transaction, repo).ConfigureAwait(false);
frames.Push(frame);
for(int i = 0; i < frame.Transaction.Inputs.Count; i++)
foreach (TxIn transactionInput in frame.Transaction.Inputs.RemoveChangePointer())
{
frames.Push(new ColoredFrame()
{
TransactionId = frame.Transaction.Inputs[i].PrevOut.Hash
TransactionId = transactionInput.PrevOut.Hash
});
}
frame.Transaction = frame.TransactionId == txId ? frame.Transaction : null; //Do not waste memory, will refetch later
......@@ -180,9 +181,15 @@ namespace NBitcoin.OpenAsset
}
else
{
skipped = 0;
for(int i = 0; i < frame.Transaction.Inputs.Count; i++)
{
frame.PreviousTransactions[i] = coloreds.Pop();
if (frame.Transaction.Inputs[i].IsChangePointer())
{
skipped++;
continue;
}
frame.PreviousTransactions[i - skipped] = coloreds.Pop();
}
}
......@@ -200,10 +207,16 @@ namespace NBitcoin.OpenAsset
}
var spentCoins = new List<ColoredCoin>();
skipped = 0;
for(int i = 0; i < frame.Transaction.Inputs.Count; i++)
{
if (frame.Transaction.Inputs[i].IsChangePointer())
{
skipped++;
continue;
}
TxIn txIn = frame.Transaction.Inputs[i];
ColoredEntry entry = frame.PreviousTransactions[i].GetColoredEntry(txIn.PrevOut.N);
ColoredEntry entry = frame.PreviousTransactions[i - skipped].GetColoredEntry(txIn.PrevOut.N);
if(entry != null)
spentCoins.Add(new ColoredCoin(entry.Asset, new Coin(txIn.PrevOut, new TxOut())));
}
......
using System.Collections.Generic;
using System.Linq;
namespace NBitcoin.Policy
{
public class DeStreamMinerTransactionPolicy : ITransactionPolicy
{
private DeStreamMinerTransactionPolicy()
{
}
public static DeStreamMinerTransactionPolicy Instance { get; } = new DeStreamMinerTransactionPolicy();
public virtual TransactionPolicyError[] Check(Transaction transaction, ICoin[] spentCoins)
{
spentCoins = spentCoins ?? new ICoin[0];
var errors = new List<TransactionPolicyError>();
if (transaction.Version > Transaction.CURRENT_VERSION || transaction.Version < 1)
{
errors.Add(new TransactionPolicyError("Invalid transaction version, expected " +
Transaction.CURRENT_VERSION));
}
IEnumerable<IGrouping<OutPoint, IndexedTxIn>> dups = transaction.Inputs.AsIndexedInputs()
.GroupBy(i => i.PrevOut);
errors.AddRange(from dup in dups
select dup.ToArray()
into duplicates
where duplicates.Length != 1
select new DuplicateInputPolicyError(duplicates));
errors.AddRange(from input in transaction.Inputs.AsIndexedInputs().RemoveChangePointer()
let coin = spentCoins.FirstOrDefault(s => s.Outpoint == input.PrevOut)
where coin == null
select new CoinNotFoundPolicyError(input));
errors.AddRange(from output in transaction.Outputs.AsCoins()
where output.Amount < Money.Zero
select new OutputPolicyError("Output value should not be less than zero", (int) output.Outpoint.N));
Money fees = transaction.GetFee(spentCoins);
if (fees != null)
{
if (fees < Money.Zero)
errors.Add(new NotEnoughFundsPolicyError("Not enough funds in this transaction", -fees));
}
TransactionCheckResult check = transaction.Check();
if (check != TransactionCheckResult.Success)
errors.Add(new TransactionPolicyError("Context free check of the transaction failed " + check));
return errors.ToArray();
}
}
}
\ No newline at end of file
......@@ -65,7 +65,7 @@ namespace NBitcoin.Policy
#region ITransactionPolicy Members
public TransactionPolicyError[] Check(Transaction transaction, ICoin[] spentCoins)
public virtual TransactionPolicyError[] Check(Transaction transaction, ICoin[] spentCoins)
{
spentCoins = spentCoins ?? new ICoin[0];
var errors = new List<TransactionPolicyError>();
......
......@@ -1359,7 +1359,7 @@ namespace NBitcoin
/// <param name="expectedFees">The expected fees (more or less 10%)</param>
/// <param name="errors">Detected errors</param>
/// <returns>True if no error</returns>
public bool Verify(Transaction tx, Money expectedFees, out TransactionPolicyError[] errors)
public virtual bool Verify(Transaction tx, Money expectedFees, out TransactionPolicyError[] errors)
{
if(tx == null)
throw new ArgumentNullException("tx");
......@@ -1429,7 +1429,7 @@ namespace NBitcoin
return Check(tx, null as Money);
}
private CoinNotFoundException CoinNotFound(IndexedTxIn txIn)
protected CoinNotFoundException CoinNotFound(IndexedTxIn txIn)
{
return new CoinNotFoundException(txIn);
}
......@@ -1777,7 +1777,7 @@ namespace NBitcoin
}
private Transaction _CompletedTransaction;
protected Transaction _CompletedTransaction;
/// <summary>
/// Allows to keep building on the top of a partially built transaction
......@@ -1798,7 +1798,7 @@ namespace NBitcoin
/// Will cover the remaining amount of TxOut of a partially built transaction (to call after ContinueToBuild)
/// </summary>
/// <returns></returns>
public TransactionBuilder CoverTheRest()
public virtual TransactionBuilder CoverTheRest()
{
if(this._CompletedTransaction == null)
throw new InvalidOperationException("A partially built transaction should be specified by calling ContinueToBuild");
......
......@@ -10,6 +10,11 @@ namespace NBitcoin
return txInList.Where(p => p.PrevOut.Hash != uint256.Zero);
}
public static IEnumerable<IndexedTxIn> RemoveChangePointer(this IEnumerable<IndexedTxIn> indexedTxIns)
{
return indexedTxIns.Where(p => p.PrevOut.Hash != uint256.Zero);
}
public static IEnumerable<uint> GetChangePointers(this TxInList txInList)
{
return txInList.Where(p => p.PrevOut.Hash == uint256.Zero).Select(p => p.PrevOut.N);
......
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