public Block CreateBlock(UInt256 previousBlockHash, int txCount, UInt256 target = null, DateTimeOffset? time = null)
{
// get the previous block's time, or 1 second ago if there is none
var prevBlockTime = blocks.LastOrDefault()?.Header?.Time ?? DateTimeOffset.Now - TimeSpan.FromSeconds(1);
// use the previous block's time + 1 second as the new block time, or the manually specified time
var thisBlockTime = time ?? prevBlockTime + TimeSpan.FromSeconds(1);
var coinbaseTx = Transaction.Create
(
version: 0,
inputs: ImmutableArray.Create
(
new TxInput
(
prevTxHash: UInt256.Zero,
prevTxOutputIndex: uint.MaxValue,
// coinbase scriptSignature must be 2-100 bytes long
scriptSignature: random.NextBytes(2 + random.Next(99)).ToImmutableArray(),
sequence: 0
)
),
outputs: ImmutableArray.Create
(
new TxOutput
(
value: 50 * SATOSHI_PER_BTC,
scriptPublicKey: this.txManager.CreatePublicKeyScript(coinbasePublicKey).ToImmutableArray()
)
),
lockTime: 0
).Transaction;
var transactionsBuilder = ImmutableArray.CreateBuilder<Transaction>(txCount + 1);
transactionsBuilder.Add(coinbaseTx);
var prevTx = coinbaseTx;
for (var i = 1; i < transactionsBuilder.Capacity; i++)
{
var outputs =
i % 2 == 0 ?
ImmutableArray.Create(
new TxOutput(prevTx.Outputs[0].Value - 1, coinbaseTx.Outputs[0].ScriptPublicKey),
new TxOutput(1, coinbaseTx.Outputs[0].ScriptPublicKey))
:
ImmutableArray.Create(new TxOutput(prevTx.Outputs[0].Value - 1, coinbaseTx.Outputs[0].ScriptPublicKey));
var tx = Transaction.Create(
version: 0,
inputs: ImmutableArray.Create(new TxInput(prevTx.Hash, 0, new byte[100].ToImmutableArray(), 0)),
outputs: outputs,
lockTime: 0).Transaction;
transactionsBuilder.Add(tx);
prevTx = tx;
}
var transactions = transactionsBuilder.MoveToImmutable();
var merkleRoot = MerkleTree.CalculateMerkleRoot(transactions);
var block = Block.Create
(
header: BlockHeader.Create
(
version: 0,
previousBlock: previousBlockHash,
merkleRoot: merkleRoot,
time: thisBlockTime,
bits: DataCalculator.ToCompact(target ?? UnitTestParams.Target0),
nonce: 0
),
transactions: transactions
);
return block;
}