void DispatchBlock() { try { _Hasher.Pause("dispatching block"); MinerTrace.Information($"dispatching block with {_ValidatedTxs.Count()} txs"); var txs = FSharpList <Types.Transaction> .Cons(_Coinbase, ListModule.OfSeq(_ValidatedTxs.Select(TransactionValidation.unpoint))); var block = new Types.Block(_Header, txs); var result = new HandleBlockAction(block).Publish().Result.BkResultEnum; if (result == BlockVerificationHelper.BkResultEnum.Accepted) { if (OnMined != null) { OnMined(block); } } else { Reset(); } MinerTrace.Information($" block {block.header.blockNumber} is " + result); } catch (Exception e) { MinerTrace.Error("Dispatch block exception", e); } }
void Main() { MinerTrace.Information("Hasher started"); while (true) { if (_Header == null) Pause("no header"); continueEvent.WaitOne(); if (_cancel.IsCancellationRequested) { break; } var time = DateTime.Now.ToUniversalTime(); var bkHash = Merkle.blockHeaderHasher.Invoke(_Header); var c = 0; if (Difficulty != 0) { var bits = new BitArray(bkHash); var len = bits.Length - 1; for (var i = 0; i < len; i++) if (!bits[len - i]) c++; else break; } if (c >= Difficulty) { MinerTrace.Information($"Hasher solved a {Difficulty} difficulty"); if (OnMined != null) OnMined(); } else { //TODO: just increment the nonce, no need to ramdon again var random = new Random(); random.NextBytes(_Header.nonce); } } MinerTrace.Information("Hasher stopped"); }
void Populate() { _BlockChainListener.Pause(); _TransactionQueue.Clear(); lock (_BlockChain.memPool.TxPool) { foreach (var item in _BlockChain.memPool.TxPool) { _TransactionQueue.Push(item.Value); } } MinerTrace.Information($"Populated, having {_TransactionQueue.Count} txs"); RecalculateHeader(); _BlockChainListener.Continue(); }
void OnBlockChainMessage(BlockChainMessage m) { _Hasher.Pause("BlockChain message"); if (m is TxMessage) { MinerTrace.Information($"Got tx ({((TxMessage)m).State})"); if (((TxMessage)m).State == TxStateEnum.Unconfirmed) { _TransactionQueue.Push(((TxMessage)m).Ptx); } RecalculateHeader(); } else if (m is BlockMessage) { MinerTrace.Information("Got bk"); Reset(); } }
void RecalculateHeader() { if (_BlockChain.Tip == null) { return; } if (_TransactionQueue.IsStuck) { MinerTrace.Information("Queue is stuck. count = " + _TransactionQueue.Count); } while (!_TransactionQueue.IsStuck && _ValidatedTxs.Count < TxsPerBlockLimit) { var ptx = _TransactionQueue.Take(); if (IsTransactionValid(ptx)) { _ValidatedTxs.Add(ptx); _TransactionQueue.Remove(); HandleTx(ptx); } else { MinerTrace.Information("Tx invalid"); _TransactionQueue.Next(); } } if (_ValidatedTxs.Count == 0) { MinerTrace.Information("No txs"); return; // don't allow empty blocks } CalculateCoinbase(); var txs = ListModule.OfSeq(FSharpList <Types.Transaction> .Cons(_Coinbase, ListModule.OfSeq(_ValidatedTxs.Select(TransactionValidation.unpoint)))); _Header = new Types.BlockHeader( 0, _BlockChain.Tip.Key, _BlockChain.Tip.Value.header.blockNumber + 1, Merkle.merkleRoot( new byte[] { }, Merkle.transactionHasher, txs ), new byte[] { }, new byte[] { }, ListModule.Empty <byte[]>(), DateTime.Now.ToUniversalTime().Ticks, Difficulty, new byte[12] ); MinerTrace.Information($"Mining block number {_BlockChain.Tip.Value.header.blockNumber + 1} with {_ValidatedTxs.Count()} txs"); _Hasher.SetHeader(_Header); _Hasher.Continue(); }
bool IsTransactionValid(TransactionValidation.PointedTransaction ptx) { if (!HasUtxos(ptx)) { MinerTrace.Information("could not validate tx - utxo missing"); return(false); } var utxoLookup = UtxoLookup.FromConverter(outpoint => { var outputs = _UtxoSet.Where(t => t.Item1.Equals(outpoint)).Select(t => t.Item2); return(!outputs.Any() ? FSharpOption <Types.Output> .None : new FSharpOption <Types.Output>(outputs.First())); }); var contractLookup = FSharpFunc <byte[], FSharpOption <ContractFunction> > .FromConverter(contractHash => { if (!_ActiveContracts.Contains(contractHash)) { return(FSharpOption <ContractFunction> .None); } try { var code = new GetContractCodeAction(contractHash).Publish().Result; //TODO: module name var extration = ContractExamples.FStarExecution.extract(System.Text.Encoding.ASCII.GetString(code)); if (FSharpOption <string> .get_IsNone(extration)) { MinerTrace.Information("Could not extract contract"); return(null); } var compilation = ContractExamples.FStarExecution.compile(extration.Value); if (FSharpOption <byte[]> .get_IsNone(compilation)) { MinerTrace.Information("Could not complie contract"); return(null); } return(ContractExamples.FStarExecution.deserialize(compilation.Value).Value.Item1); } catch (Exception e) { MinerTrace.Error("Could not compile contract " + Convert.ToBase64String(contractHash), e); return(null); } }); if (!TransactionValidation.validateNonCoinbaseTx( ptx, utxoLookup, contractLookup )) { MinerTrace.Information("could not validate tx"); return(false); } MinerTrace.Information("validated tx"); //TODO: memory management issues. trying to explicitly collect DynamicMethods GC.Collect(); GC.WaitForPendingFinalizers(); return(true); }
public void Continue() { MinerTrace.Information("Hasher resumed"); continueEvent.Set(); }
public void Pause(string reason) { MinerTrace.Information("Hasher paused: " + reason); continueEvent.Reset(); }