Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix the coinstake flag and allow the invalid trx #10

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public override void Initialize()
base.Initialize();

this.consensus = this.Parent.Network.Consensus;
var consensusRules = (PosConsensusRuleEngine) this.Parent;
var consensusRules = (PosConsensusRuleEngine)this.Parent;

this.stakeValidator = consensusRules.StakeValidator;
this.stakeChain = consensusRules.StakeChain;
Expand Down Expand Up @@ -106,6 +106,13 @@ public override void CheckMaturity(UnspentOutputs coins, int spendHeight)
if (coins.IsCoinstake)
if (spendHeight - coins.Height < this.consensus.CoinbaseMaturity)
{
if (coins.TransactionId == new uint256("29e5636769fec7a173d4351c2a6241b2d9d02bccd1b4a865c996d24c85f189ef"))
{
// There is a special case trx in the chain that was allowed immature trx to be spent before its time.
// After the issue was fixed we allowed the trx to pass
return;
}

this.Logger.LogDebug(
"Coinstake transaction height {0} spent at height {1}, but maturity is set to {2}.",
coins.Height, spendHeight, this.consensus.CoinbaseMaturity);
Expand All @@ -130,7 +137,7 @@ protected override void CheckInputValidity(Transaction transaction, UnspentOutpu
/// <param name="context">Context that contains variety of information regarding blocks validation and execution.</param>
/// <exception cref="ConsensusErrors.PrevStakeNull">Thrown if previous stake is not found.</exception>
/// <exception cref="ConsensusErrors.SetStakeEntropyBitFailed">Thrown if failed to set stake entropy bit.</exception>
void CheckAndComputeStake(RuleContext context)
private void CheckAndComputeStake(RuleContext context)
{
var chainedHeader = context.ValidationContext.ChainedHeaderToValidate;
var block = context.ValidationContext.BlockToValidate;
Expand Down
55 changes: 32 additions & 23 deletions src/components/NBitcoin/BitcoinCore/Coins.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ namespace NBitcoin.BitcoinCore
public class Coins : IBitcoinSerializable
{
public static readonly TxOut NullTxOut = new TxOut(new Money(-1), Script.Empty);
bool fCoinStake;
uint nHeight;
uint nTime;
uint nVersion;
private bool fCoinStake;
private uint nHeight;
private uint nTime;
private uint nVersion;

public Coins()
{
Expand All @@ -26,7 +26,7 @@ public Coins(Transaction tx, int height)
this.CoinBase = tx.IsCoinBase;
this.Outputs = tx.Outputs.ToList();
this.nVersion = tx.Version;
this.nHeight = (uint) height;
this.nHeight = (uint)height;

ClearUnspendable();
UpdateValue();
Expand Down Expand Up @@ -64,27 +64,28 @@ public uint Version

// Lists unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped.
public List<TxOut> Outputs { get; private set; } = new List<TxOut>();

public Money Value { get; private set; }
public bool IsEmpty => this.Outputs.Count == 0;

public int UnspentCount => this.Outputs.Count(c => !IsNull(c));

void UpdateValue()
private void UpdateValue()
{
this.Value = this.Outputs
.Where(o => !IsNull(o))
.Sum(o => o.Value);
}

bool IsNull(TxOut o)
private bool IsNull(TxOut o)
{
return o.Value.Satoshi == -1;
}

/// <summary>
/// Remove the last items that are <see cref="IsNull" />, this method may reduce the size of the collection.
/// </summary>
void Cleanup()
private void Cleanup()
{
var count = this.Outputs.Count;

Expand Down Expand Up @@ -133,7 +134,7 @@ public void ReadWrite(BitcoinStream stream)

var fFirst = this.Outputs.Count > 0 && !IsNull(this.Outputs[0]);
var fSecond = this.Outputs.Count > 1 && !IsNull(this.Outputs[1]);
var nCode = unchecked((uint) (8 * (nMaskCode - (fFirst || fSecond ? 0 : 1)) + (this.CoinBase ? 1 : 0) +
var nCode = unchecked((uint)(8 * (nMaskCode - (fFirst || fSecond ? 0 : 1)) + (this.CoinBase ? 1 : 0) +
(fFirst ? 2 : 0) + (fSecond ? 4 : 0)));

// version
Expand All @@ -147,17 +148,17 @@ public void ReadWrite(BitcoinStream stream)
{
byte chAvail = 0;
for (uint i = 0; i < 8 && 2 + b * 8 + i < this.Outputs.Count; i++)
if (!IsNull(this.Outputs[2 + (int) b * 8 + (int) i]))
chAvail |= (byte) (1 << (int) i);
if (!IsNull(this.Outputs[2 + (int)b * 8 + (int)i]))
chAvail |= (byte)(1 << (int)i);

stream.ReadWrite(ref chAvail);
}

// txouts themself
for (uint i = 0; i < this.Outputs.Count; i++)
if (!IsNull(this.Outputs[(int) i]))
if (!IsNull(this.Outputs[(int)i]))
{
var compressedTx = new TxOutCompressor(this.Outputs[(int) i]);
var compressedTx = new TxOutCompressor(this.Outputs[(int)i]);
stream.ReadWrite(ref compressedTx);
}

Expand All @@ -170,6 +171,10 @@ public void ReadWrite(BitcoinStream stream)
stream.ReadWrite(ref this.fCoinStake);
stream.ReadWrite(ref this.nTime);
}
else
{
stream.ReadWrite(ref this.fCoinStake);
}
}
else
{
Expand All @@ -182,11 +187,11 @@ public void ReadWrite(BitcoinStream stream)
stream.ReadWriteAsVarInt(ref nCode);
this.CoinBase = (nCode & 1) != 0;

var vAvail = new List<bool> {false, false};
var vAvail = new List<bool> { false, false };
vAvail[0] = (nCode & 2) != 0;
vAvail[1] = (nCode & 4) != 0;

var nMaskCode = unchecked((uint) (nCode / 8 + ((nCode & 6) != 0 ? 0 : 1)));
var nMaskCode = unchecked((uint)(nCode / 8 + ((nCode & 6) != 0 ? 0 : 1)));

//// spentness bitmask
while (nMaskCode > 0)
Expand All @@ -197,7 +202,7 @@ public void ReadWrite(BitcoinStream stream)

for (uint p = 0; p < 8; p++)
{
var f = (chAvail & (1 << (int) p)) != 0;
var f = (chAvail & (1 << (int)p)) != 0;
vAvail.Add(f);
}

Expand All @@ -208,11 +213,11 @@ public void ReadWrite(BitcoinStream stream)
// txouts themself
this.Outputs = Enumerable.Range(0, vAvail.Count).Select(_ => NullTxOut).ToList();
for (uint i = 0; i < vAvail.Count; i++)
if (vAvail[(int) i])
if (vAvail[(int)i])
{
var compressed = new TxOutCompressor();
stream.ReadWrite(ref compressed);
this.Outputs[(int) i] = compressed.TxOut;
this.Outputs[(int)i] = compressed.TxOut;
}

//// coinbase height
Expand All @@ -224,6 +229,10 @@ public void ReadWrite(BitcoinStream stream)
stream.ReadWrite(ref this.fCoinStake);
stream.ReadWrite(ref this.nTime);
}
else
{
stream.ReadWrite(ref this.fCoinStake);
}

Cleanup();
UpdateValue();
Expand All @@ -233,15 +242,15 @@ public void ReadWrite(BitcoinStream stream)
// calculate number of bytes for the bitmask, and its number of non-zero bytes
// each bit in the bitmask represents the availability of one output, but the
// availabilities of the first two outputs are encoded separately
void CalcMaskSize(ref uint nBytes, ref uint nNonzeroBytes)
private void CalcMaskSize(ref uint nBytes, ref uint nNonzeroBytes)
{
uint nLastUsedByte = 0;

for (uint b = 0; 2 + b * 8 < this.Outputs.Count; b++)
{
var fZero = true;
for (uint i = 0; i < 8 && 2 + b * 8 + i < this.Outputs.Count; i++)
if (!IsNull(this.Outputs[2 + (int) b * 8 + (int) i]))
if (!IsNull(this.Outputs[2 + (int)b * 8 + (int)i]))
{
fZero = false;
}
Expand All @@ -259,21 +268,21 @@ void CalcMaskSize(ref uint nBytes, ref uint nNonzeroBytes)
// check whether a particular output is still available
public bool IsAvailable(uint position)
{
return position <= int.MaxValue && position < this.Outputs.Count && !IsNull(this.Outputs[(int) position]);
return position <= int.MaxValue && position < this.Outputs.Count && !IsNull(this.Outputs[(int)position]);
}

public TxOut TryGetOutput(uint position)
{
if (!IsAvailable(position))
return null;

return this.Outputs[(int) position];
return this.Outputs[(int)position];
}

// check whether the entire CCoins is spent
// note that only !IsPruned() CCoins can be serialized
public bool IsPruned => this.IsEmpty || this.Outputs.All(v => IsNull(v));

#endregion
#endregion IBitcoinSerializable Members
}
}