public void SetUndoData( TransactionContext transactionContext, byte[] block, BlockUndoData blockUndoData) { BlockUndo.Put(transactionContext, block, blockUndoData); }
bool ExtendMain(List <QueueAction> queuedActions, double totalWork, bool isGenesis = false) { if (_BlockChain.BlockStore.ContainsKey(_DbTx, _BkHash)) { _BlockChain.BlockStore.SetLocation(_DbTx, _BkHash, LocationEnum.Main); } else { _BlockChain.BlockStore.Put(_DbTx, _BkHash, _Bk, LocationEnum.Main, totalWork); } _BlockChain.Timestamps.Push(_Bk.header.timestamp); if (_Bk.header.blockNumber % 2000 == 0) { _BlockChain.BlockNumberDifficulties.Add(_DbTx.Transaction, _Bk.header.blockNumber, _BkHash); } var blockUndoData = new BlockUndoData(); var confirmedTxs = new HashDictionary <TransactionValidation.PointedTransaction>(); //TODO: lock with mempool for (var txIdx = 0; txIdx < _Bk.transactions.Count(); txIdx++) { var tx = _Bk.transactions[txIdx]; var txHash = Merkle.transactionHasher.Invoke(tx); TransactionValidation.PointedTransaction ptx; if (!isGenesis) { if ((txIdx == 0 && !IsCoinbaseTxValid(tx)) || (txIdx > 0 && IsCoinbaseTxValid(tx))) { if (txIdx == 0) { BlockChainTrace.Information("Invalid coinbase tx"); } else { BlockChainTrace.Information($"Invalid tx ({txIdx})"); } return(false); } if (!IsTransactionValid(tx, txHash, out ptx)) { return(false); } confirmedTxs[txHash] = ptx; foreach (var pInput in ptx.pInputs) { _BlockChain.UTXOStore.Remove(_DbTx, pInput.Item1); BlockChainTrace.Information($"utxo spent, amount {pInput.Item2.spend.amount}", ptx); //BlockChainTrace.Information($" of", pInput.Item1.txHash); blockUndoData.RemovedUTXO.Add(new Tuple <Types.Outpoint, Types.Output>(pInput.Item1, pInput.Item2)); } } else { ptx = TransactionValidation.toPointedTransaction( tx, ListModule.Empty <Types.Output>() ); } _BlockChain.BlockStore.TxStore.Put(_DbTx, txHash, tx, true); var contractExtendSacrifices = new HashDictionary <ulong>(); var activationSacrifice = 0UL; for (var outputIdx = 0; outputIdx < tx.outputs.Count(); outputIdx++) { var output = tx.outputs[outputIdx]; 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 && contractSacrificeLock.Item.lockData[0] != null && contractSacrificeLock.Item.lockData[0].Length > 0) { var contractKey = contractSacrificeLock.Item.lockData[0]; // output-lock-level indicated contract contractExtendSacrifices[contractKey] = (contractExtendSacrifices.ContainsKey(contractKey) ? contractExtendSacrifices[contractKey] : 0) + output.spend.amount; } else 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]) { BlockChainTrace.Information($"new utxo, amount {output.spend.amount}", tx); var outpoint = new Types.Outpoint(txHash, (uint)outputIdx); _BlockChain.UTXOStore.Put(_DbTx, outpoint, output); blockUndoData.AddedUTXO.Add(new Tuple <Types.Outpoint, Types.Output>(outpoint, output)); } } if (FSharpOption <Types.ExtendedContract> .get_IsSome(tx.contract) && !tx.contract.Value.IsHighVContract) { var codeBytes = ((Types.ExtendedContract.Contract)tx.contract.Value).Item.code; var contractHash = Merkle.innerHash(codeBytes); var contractCode = System.Text.Encoding.ASCII.GetString(codeBytes); if (_BlockChain.ActiveContractSet.TryActivate(_DbTx, contractCode, activationSacrifice, contractHash, _Bk.header.blockNumber)) { blockUndoData.ACSDeltas.Add(contractHash, new ACSUndoData()); ContractsTxsStore.Add(_DbTx.Transaction, contractHash, txHash); } } foreach (var item in contractExtendSacrifices) { var currentACSItem = _BlockChain.ActiveContractSet.Get(_DbTx, item.Key); if (currentACSItem.Value != null) { if (_BlockChain.ActiveContractSet.TryExtend(_DbTx, item.Key, item.Value)) { if (!blockUndoData.ACSDeltas.ContainsKey(item.Key)) { blockUndoData.ACSDeltas.Add(item.Key, new ACSUndoData() { LastBlock = currentACSItem.Value.LastBlock }); } } } } } var expiringContracts = _BlockChain.ActiveContractSet.GetExpiringList(_DbTx, _Bk.header.blockNumber); foreach (var acsItem in expiringContracts) { if (!blockUndoData.ACSDeltas.ContainsKey(acsItem.Key)) { blockUndoData.ACSDeltas.Add(acsItem.Key, new ACSUndoData() { ACSItem = acsItem.Value }); } } if (!isGenesis) { _BlockChain.BlockStore.SetUndoData(_DbTx, _BkHash, blockUndoData); } _BlockChain.ActiveContractSet.DeactivateContracts(_DbTx, expiringContracts.Select(t => t.Key)); ValidateACS(); _BlockChain.ChainTip.Context(_DbTx).Value = _BkHash; //TODO: only update after commit _BlockChain.Tip = new Keyed <Types.Block>(_BkHash, _Bk); queuedActions.Add(new MessageAction(new BlockMessage(confirmedTxs, _Bk.header.blockNumber))); foreach (var item in confirmedTxs) { ConfirmedTxs[item.Key] = item.Value; UnconfirmedTxs.Remove(item.Key); } return(true); }