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(); }
void HandleTx(TransactionValidation.PointedTransaction ptx) { //TODO: try simplify using hash from message var txHash = Merkle.transactionHasher.Invoke(TransactionValidation.unpoint(ptx)); var activationSacrifice = 0UL; for (var i = 0; i < ptx.outputs.Length; i++) { var output = ptx.outputs[i]; if ([email protected]) { if (!output.spend.asset.SequenceEqual(Tests.zhash)) { continue; // not Zen } var contractSacrificeLock = (Types.OutputLock.ContractSacrificeLock)output.@lock; if (contractSacrificeLock.IsHighVLock) { continue; // not current version } if (contractSacrificeLock.Item.lockData.Length == 0) { activationSacrifice += output.spend.amount; } } //todo: fix to exclude CSLocks&FLocks, instead of including by locktype if ([email protected] || [email protected]) { var outpoint = new Types.Outpoint(txHash, (uint)i); _UtxoSet.Add(new Tuple <Types.Outpoint, Types.Output>(outpoint, output)); } } if (FSharpOption <Types.ExtendedContract> .get_IsSome(ptx.contract) && !ptx.contract.Value.IsHighVContract) { var codeBytes = ((Types.ExtendedContract.Contract)ptx.contract.Value).Item.code; var contractHash = Merkle.innerHash(codeBytes); var contractCode = System.Text.Encoding.ASCII.GetString(codeBytes); if (!_ActiveContracts.Contains(contractHash)) { if (activationSacrifice > ActiveContractSet.KalapasPerBlock(contractCode)) { try { var compiledCodeOpt = ContractExamples.FStarExecution.compile(contractCode); if (FSharpOption <byte[]> .get_IsSome(compiledCodeOpt)) { _ActiveContracts.Add(contractHash); } } catch (Exception e) { MinerTrace.Error("Could not compile contract " + Convert.ToBase64String(contractHash), e); } } } } }
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(); }