public TxMessage(byte[] txHash, TransactionValidation.PointedTransaction ptx, TxStateEnum state) { BlockChainTrace.Information("To wallet: " + state, txHash); TxHash = txHash; Ptx = ptx; State = state; }
public static IsContractGeneratedTxResult IsContractGeneratedTx(TransactionValidation.PointedTransaction ptx, out byte[] contractHash) { contractHash = null; foreach (var input in ptx.pInputs) { if ([email protected]) { if (contractHash == null) { contractHash = ((Types.OutputLock.ContractLock)input.Item2.@lock).contractHash; } else if (!contractHash.SequenceEqual(((Types.OutputLock.ContractLock)input.Item2.@lock).contractHash)) { return(IsContractGeneratedTxResult.Invalid); } else if (!contractHash.SequenceEqual(((Types.OutputLock.ContractLock)input.Item2.@lock).contractHash)) { BlockChainTrace.Information("Unexpected contactHash", contractHash); return(IsContractGeneratedTxResult.Invalid); } } } return(contractHash == null ? IsContractGeneratedTxResult.NotContractGenerated : IsContractGeneratedTxResult.ContractGenerated); }
// remove bool IsTransactionValid(Types.Transaction tx, byte[] txHash, out TransactionValidation.PointedTransaction ptx) { if (_BlockChain.BlockStore.TxStore.ContainsKey(_DbTx, txHash) && _BlockChain.BlockStore.TxStore.Get(_DbTx, txHash).Value.InMainChain) { BlockChainTrace.Information("Tx already in store", txHash); ptx = null; return(false); } switch (_BlockChain.IsOrphanTx(_DbTx, tx, true, out ptx)) { case BlockChain.IsTxOrphanResult.Orphan: BlockChainTrace.Information("tx invalid - orphan", tx); return(false); case BlockChain.IsTxOrphanResult.Invalid: BlockChainTrace.Information("tx invalid - reference(s)", tx); return(false); } if (_BlockChain.IsDoubleSpend(_DbTx, tx, true)) { return(false); } //TODO: coinbase validation + check that witness has blocknumber if (!BlockChain.IsValidUserGeneratedTx(_DbTx, ptx)) { BlockChainTrace.Information("tx invalid - structural", ptx); return(false); } byte[] contractHash; switch (BlockChain.IsContractGeneratedTx(ptx, out contractHash)) { case BlockChain.IsContractGeneratedTxResult.ContractGenerated: if (!_BlockChain.ActiveContractSet.IsActive(_DbTx, contractHash)) { BlockChainTrace.Information("tx invalid - contract not active", tx); return(false); } var contractFunction = _BlockChain.ActiveContractSet.GetContractFunction(_DbTx, contractHash); if (!BlockChain.IsValidAutoTx(ptx, UtxoLookup, contractHash, contractFunction)) { BlockChainTrace.Information("auto-tx invalid", ptx); return(false); } break; case BlockChain.IsContractGeneratedTxResult.Invalid: BlockChainTrace.Information("tx invalid - input locks", tx); return(false); } return(true); }
//Types.Output GetUTXO(Types.Outpoint outpoint, bool IsInBlock) //{ // using (TransactionContext dbTx = _DBContext.GetTransactionContext()) // { // return GetUTXO(outpoint, dbTx, IsInBlock); // } //} public UtxoLookup UtxoLookupFactory(TransactionContext dbTx, bool isInBlock, TransactionValidation.PointedTransaction ptx = null) { return(UtxoLookup.FromConverter(t => { bool valid; var output = GetUTXO(t, dbTx, isInBlock, out valid, ptx); return output == null ? FSharpOption <Types.Output> .None : new FSharpOption <Types.Output>(output); })); }
public static bool IsValidAutoTx(TransactionValidation.PointedTransaction ptx, UtxoLookup UtxoLookup, byte[] contractHash, ContractFunction contractFunction) { var isWitness = false; var witnessIdx = -1; byte[] message = null; for (var i = 0; i < ptx.witnesses.Length; i++) { if (ptx.witnesses[i].Length > 0) { witnessIdx = i; } } if (witnessIdx == 0) { message = ptx.witnesses[0]; } else if (witnessIdx == -1) { var contractLock = ptx.pInputs[0].Item2.@lock as Types.OutputLock.ContractLock; if (contractLock == null) { BlockChainTrace.Information("expected ContractLock, tx invalid"); return(false); } message = contractLock.data; } isWitness = witnessIdx == 0; Types.Transaction tx; var isExecutionSuccessful = ExecuteContract( contractHash, contractFunction, message, out tx, UtxoLookup, isWitness ); return(isExecutionSuccessful && tx != null && TransactionValidation.unpoint(ptx).Equals(tx)); }
public static bool IsValidUserGeneratedTx(TransactionContext dbTx, TransactionValidation.PointedTransaction ptx) { //Verify crypto signatures for each input; reject if any are bad //Using the referenced output transactions to get input values, check that each input value, as well as the sum, are in legal money range //Reject if the sum of input values < sum of output values //for (var i = 0; i < ptx.pInputs.Length; i++) //{ // if (!TransactionValidation.validateAtIndex(ptx, i)) // return false; //} return(true); }
bool IsReferencedCoinbaseTxsValid(TransactionContext dbTx, TransactionValidation.PointedTransaction ptx) { var currentHeight = Tip == null ? 0 : Tip.Value.header.blockNumber; foreach (var refTx in ptx.pInputs.Select(t => t.Item1.txHash)) { Types.BlockHeader refTxBk; if (BlockStore.IsCoinbaseTx(dbTx, refTx, out refTxBk)) { if (refTxBk.blockNumber - currentHeight < COINBASE_MATURITY) { return(false); } } } return(true); }
//TODO: refactore for efficiency bool HasUtxos(TransactionValidation.PointedTransaction ptx) { foreach (var input in ptx.pInputs) { foreach (var tx in _ValidatedTxs) { foreach (var txInput in tx.pInputs) { if (input.Item1.Equals(txInput)) { return(false); } } } } foreach (var input in ptx.pInputs) { foreach (var tx in _ValidatedTxs) { var txHash = Merkle.transactionHasher.Invoke(TransactionValidation.unpoint(ptx)); for (var i = 0; i < tx.outputs.Length; i++) { var outpoint = new Types.Outpoint(txHash, (uint)i); if (input.Item1.Equals(outpoint)) { return(true); } } } } foreach (var input in ptx.pInputs) { if (!_UtxoSet.Any(t => t.Item1.Equals(input.Item1))) { return(false); } } return(true); }
void HandleTx(TransactionContext dbTx, byte[] txHash, TransactionValidation.PointedTransaction ptx, List <TxDelta> deltas, TxStateEnum txState) { var isValid = txState != TxStateEnum.Invalid; var _deltas = new AssetDeltas(); if (!isValid) { foreach (var item in _TxStore.All(dbTx).Where(t => t.Item2.TxHash.SequenceEqual(txHash))) { item.Item2.TxState = txState; //TODO: handle ui consistency _TxStore.Put(dbTx, item.Item1, item.Item2); } return; } ptx.outputs.Where(IsMatch).ToList().ForEach(o => { AddOutput(_deltas, o, !isValid); }); ptx.pInputs.ToList().ForEach(pInput => { var key = GetKey(pInput.Item2); if (key != null) { AddOutput(_deltas, pInput.Item2, isValid); _KeyStore.Used(dbTx, key, true); } }); if (_deltas.Count > 0) { var tx = TransactionValidation.unpoint(ptx); _TxStore.Put(dbTx, txHash, tx, _deltas, txState); deltas.Add(new TxDelta(txState, txHash, tx, _deltas)); } }
public override bool IsDoubleSpend(TransactionValidation.PointedTransaction t, IEnumerable <Types.Outpoint> spentOutputs) { return(t.pInputs.Select(_t => _t.Item1).Any(_t => spentOutputs.Contains(_t))); }
Types.Output GetUTXO(Types.Outpoint outpoint, TransactionContext dbTx, bool isInBlock, out bool valid, TransactionValidation.PointedTransaction validatingPtx = null) { valid = true; if (!isInBlock) { foreach (var item in memPool.TxPool) { foreach (var pInput in item.Value.pInputs) { if (outpoint.Equals(pInput.Item1)) { return(null); } } } } var result = UTXOStore.Get(dbTx, outpoint); if (result != null) { return(result.Value); } if (isInBlock) { return(null); } if (!memPool.TxPool.Contains(outpoint.txHash)) { return(null); } if (validatingPtx == null) { var tx = memPool.TxPool[outpoint.txHash]; if (tx.outputs.Count() > outpoint.index) { return(tx.outputs[(int)outpoint.index]); } else { valid = false; } } else { foreach (var pInput in validatingPtx.pInputs) { if (outpoint.Equals(pInput.Item1)) { return(pInput.Item2); } } } return(null); }
public IsTxOrphanResult IsOrphanTx(TransactionContext dbTx, Types.Transaction tx, bool isBlock, out TransactionValidation.PointedTransaction ptx) { var outputs = new List <Types.Output>(); ptx = null; foreach (Types.Outpoint input in tx.inputs) { bool valid; var output = GetUTXO(input, dbTx, isBlock, out valid); if (!valid) { return(IsTxOrphanResult.Invalid); } if (output != null) { outputs.Add(output); } else { return(IsTxOrphanResult.Orphan); } } ptx = TransactionValidation.toPointedTransaction( tx, ListModule.OfSeq(outputs) ); return(IsTxOrphanResult.NotOrphan); }
bool IsCoinbaseTx(TransactionValidation.PointedTransaction ptx) { return(ptx.pInputs.Any(t => t.Item2.@lock is Types.OutputLock.CoinbaseLock)); }
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); }