private OperatingError _CheckTransactionGasLimit(Transaction transaction, IBlockchainSnapshot snapshot) { /* check available LA balance */ var fee = new Money(transaction.GasLimit * transaction.GasPrice); return(snapshot.Balances.GetBalance(transaction.From).CompareTo(fee) < 0 ? OperatingError.InsufficientBalance : OperatingError.Ok); }
public void SaveSnapshotForBlock(ulong block, IBlockchainSnapshot snapshot) { SetVersion((uint)RepositoryType.BalanceRepository, block, snapshot.Balances.Version); SetVersion((uint)RepositoryType.ContractRepository, block, snapshot.Contracts.Version); SetVersion((uint)RepositoryType.StorageRepository, block, snapshot.Storage.Version); SetVersion((uint)RepositoryType.TransactionRepository, block, snapshot.Transactions.Version); SetVersion((uint)RepositoryType.BlockRepository, block, snapshot.Blocks.Version); SetVersion((uint)RepositoryType.EventRepository, block, snapshot.Events.Version); SetVersion((uint)RepositoryType.ValidatorRepository, block, snapshot.Validators.Version); }
public string CheckNodeHashes(string blockTag) { var blockNumber = GetBlockNumberByTag(blockTag); IBlockchainSnapshot blockchainSnapshot = _snapshotIndexer.GetSnapshotForBlock((ulong)blockNumber); bool res = true; ISnapshot[] snapshots = blockchainSnapshot.GetAllSnapshot(); foreach (var snapshot in snapshots) { res &= snapshot.IsTrieNodeHashesOk(); } return(Web3DataFormatUtils.Web3Number(Convert.ToUInt64(res))); }
public JObject?GetAllTrieRootsHash(string blockTag) { var blockNumber = GetBlockNumberByTag(blockTag); IBlockchainSnapshot blockchainSnapshot = _snapshotIndexer.GetSnapshotForBlock((ulong)blockNumber); var trieRootsHash = new JObject { }; ISnapshot[] snapshots = blockchainSnapshot.GetAllSnapshot(); string[] snapshotNames = new string[] { "Balances", "Contracts", "Storage", "Transactions", "Blocks", "Events", "Validators" }; for (int i = 0; i < snapshots.Length; i++) { trieRootsHash[snapshots[i] + "Hash"] = Web3DataFormatUtils.Web3Data(snapshots[i].Hash); } return(trieRootsHash); }
public void RollbackTo(IBlockchainSnapshot snapshot) { if (PendingSnapshot != null) { throw new InvalidOperationException("Cannot rollback to state with unapproved changes"); } _balanceManager.RollbackTo(snapshot.Balances); _contractManager.RollbackTo(snapshot.Contracts); _storageManager.RollbackTo(snapshot.Storage); _transactionManager.RollbackTo(snapshot.Transactions); _blockManager.RollbackTo(snapshot.Blocks); _eventManager.RollbackTo(snapshot.Events); _validatorManager.RollbackTo(snapshot.Validators); LastApprovedSnapshot = snapshot; }
public string GetRootHashByTrieName(string trieName, string blockTag) { var blockNumber = GetBlockNumberByTag(blockTag); if (blockNumber == null) { return("0x"); } IBlockchainSnapshot blockchainSnapshot = _snapshotIndexer.GetSnapshotForBlock((ulong)blockNumber); var snapshot = blockchainSnapshot.GetSnapshot(trieName); if (snapshot == null) { return("0x"); } return(Web3DataFormatUtils.Web3Data(snapshot.Hash)); }
private OperatingError _InvokeContract( UInt160 addressTo, byte[] input, TransactionReceipt receipt, IBlockchainSnapshot snapshot, bool isSystemContract ) { var transaction = receipt.Transaction; var context = new InvocationContext(receipt.Transaction.From, snapshot, receipt); try { if (receipt.GasUsed > transaction.GasLimit) { return(OperatingError.OutOfGas); } var result = ContractInvoker.Invoke(addressTo, context, input, transaction.GasLimit - receipt.GasUsed); receipt.GasUsed += result.GasUsed; if (result.Status != ExecutionStatus.Ok) { return(OperatingError.ContractFailed); } if (receipt.GasUsed > transaction.GasLimit) { return(OperatingError.OutOfGas); } /* this OnSystemContractInvoked is useful for internal communication (for example - during keyGeneration) */ if (isSystemContract) { OnSystemContractInvoked?.Invoke(this, context); } return(OperatingError.Ok); } catch (OutOfGasException e) { receipt.GasUsed += e.GasUsed; } catch (Exception e) { Logger.LogWarning($"Failed contract execution: {e}"); return(OperatingError.InvalidContract); } return(OperatingError.OutOfGas); }
public string GetRootVersionByTrieName(string trieName, string blockTag) { var blockNumber = GetBlockNumberByTag(blockTag); if (blockNumber == null) { return("0x"); } IBlockchainSnapshot blockchainSnapshot = _snapshotIndexer.GetSnapshotForBlock((ulong)blockNumber); ISnapshot? snapshot = blockchainSnapshot.GetSnapshot(trieName); if (snapshot is null) { return("0x"); } else { return(Web3DataFormatUtils.Web3Number(snapshot.Version)); } }
public JObject?GetStateByNumber(string blockTag) { var blockNumber = GetBlockNumberByTag(blockTag); if (blockNumber == null) { return(null); } IBlockchainSnapshot blockchainSnapshot = _snapshotIndexer.GetSnapshotForBlock((ulong)blockNumber); var state = new JObject { }; string[] trieNames = new string[] { "Balances", "Contracts", "Storage", "Transactions", "Blocks", "Events", "Validators" }; ISnapshot[] snapshots = blockchainSnapshot.GetAllSnapshot(); for (var i = 0; i < trieNames.Length; i++) { state[trieNames[i]] = Web3DataFormatUtils.Web3Trie(snapshots[i].GetState()); state[trieNames[i] + "Root"] = Web3DataFormatUtils.Web3Number(snapshots[i].Version); } return(state); }
private OperatingError _TakeTransactionFee( TransactionReceipt transaction, IBlockchainSnapshot snapshot, out Money fee ) { fee = new Money(transaction.GasUsed * transaction.Transaction.GasPrice); /* transfer fee from wallet to validator */ if (fee == Money.Zero) { return(OperatingError.Ok); } /* check available LA balance */ var senderBalance = snapshot.Balances.GetBalance(transaction.Transaction.From); if (senderBalance < fee) { return(OperatingError.InsufficientBalance); } return(!snapshot.Balances.TransferBalance(transaction.Transaction.From, ContractRegisterer.GovernanceContract, fee) ? OperatingError.InsufficientBalance : OperatingError.Ok); }
public OperatingError Execute(Block block, TransactionReceipt receipt, IBlockchainSnapshot snapshot) { /* check gas limit */ var error = _CheckGasLimit(receipt); if (error != OperatingError.Ok) { return(error); } var transaction = receipt.Transaction; /* validate transaction before execution */ error = Verify(transaction); if (error != OperatingError.Ok) { return(error); } if (block.Header.Index == 0) // genesis is special case, just mint tokens { if (!receipt.Transaction.From.Equals(UInt160Utils.Zero)) { return(OperatingError.InvalidTransaction); } if (!receipt.Transaction.Invocation.IsEmpty) { return(OperatingError.InvalidTransaction); } snapshot.Balances.AddBalance(receipt.Transaction.To, transaction.Value.ToMoney(), true); return(OperatingError.Ok); } if (receipt.Transaction.To.Buffer.IsEmpty || receipt.Transaction.To.IsZero()) // this is deploy transaction { var invocation = ContractEncoder.Encode("deploy(bytes)", transaction.Invocation.ToArray()); return(_InvokeContract(ContractRegisterer.DeployContract, invocation, receipt, snapshot, true)); } var contract = snapshot.Contracts.GetContractByHash(transaction.To); var systemContract = _contractRegisterer.GetContractByAddress(transaction.To); if (contract is null && systemContract is null) { /* * Destination address is not smart-contract, just plain address * So we just call transfer method of system contract */ if (snapshot.Balances.GetBalance(transaction.From) < transaction.Value.ToMoney()) { return(OperatingError.InsufficientBalance); } var invocation = ContractEncoder.Encode("transfer(address,uint256)", transaction.To, transaction.Value); /* LatokenContract / NativeTokenContract handles the token transfer */ return(_InvokeContract(ContractRegisterer.LatokenContract, invocation, receipt, snapshot, true)); } /* try to transfer funds from sender to recipient */ if (new Money(transaction.Value) > Money.Zero) { if (!snapshot.Balances.TransferBalance(transaction.From, transaction.To, new Money(transaction.Value))) { return(OperatingError.InsufficientBalance); } } /* invoke required function or fallback */ return(_InvokeContract( receipt.Transaction.To, receipt.Transaction.Invocation.ToArray(), receipt, snapshot, !(systemContract is null) )); }
public InvocationContext(UInt160 sender, IBlockchainSnapshot snapshot, TransactionReceipt receipt) { Sender = sender; Snapshot = snapshot; Receipt = receipt; }
private OperatingError _CheckTransactionGasPrice(Transaction transaction, IBlockchainSnapshot snapshot) { return(transaction.GasPrice >= snapshot.NetworkGasPrice || transaction.From.IsZero() ? OperatingError.Ok : OperatingError.Underpriced); }
public OperatingError Execute(Block block, TransactionReceipt receipt, IBlockchainSnapshot snapshot) { var transactionRepository = _stateManager.CurrentSnapshot.Transactions; /* check transaction with this hash in database */ if (transactionRepository.GetTransactionByHash(receipt.Hash) != null) { return(OperatingError.AlreadyExists); } /* verify transaction */ /* find if verification should be skipped for this transaction */ var indexInCycle = block.Header.Index % StakingContract.CycleDuration; var cycle = block.Header.Index / StakingContract.CycleDuration; var isGenesisBlock = block.Header.Index == 0; var isDistributeCycleRewardsAndPenaltiesTx = IsDistributeCycleRewardsAndPenaltiesTx(block, receipt.Transaction); var isFinishVrfLotteryTx = IsFinishVrfLotteryTx(block, receipt.Transaction); var isFinishCycleTx = IsFinishCycleTx(block, receipt.Transaction); // there are some cases when transaction verification is skipped // (1) genesis block's transactions // (2) DistributeCycleRewardsAndPenalties transaction. This transaction is executed during block, // (a) indexInCycle( = blockHeight % CycleDuration) == AttendanceDetectionDuration (CycleDuration / 10) // (3) FinishVrfLottery transaction. This transaction is executed during block, // (a) indexInCycle( = blockHeight % CycleDuration) == VrfSubmissionPhaseDuration (CycleDuration / 2) // (4) FinishCycle transaction. This transaction is executed during block, // (a) indexInCycle( = blockHeight % CycleDuration) == 0 // (b) cycle (= blockHeight / cycleDuration) > 0 var canTransactionMissVerification = isGenesisBlock || isDistributeCycleRewardsAndPenaltiesTx || isFinishVrfLotteryTx || isFinishCycleTx; var verifyError = VerifyInternal(receipt, canTransactionMissVerification, HardforkHeights.IsHardfork_9Active(block.Header.Index)); if (verifyError != OperatingError.Ok) { return(verifyError); } /* maybe we don't need this check, but I'm afraid */ if (!receipt.Transaction.FullHash(receipt.Signature, HardforkHeights.IsHardfork_9Active(block.Header.Index)).Equals(receipt.Hash)) { return(OperatingError.HashMismatched); } /* check transaction nonce */ var nonce = transactionRepository.GetTotalTransactionCount(receipt.Transaction.From); if (nonce != receipt.Transaction.Nonce) { return(OperatingError.InvalidNonce); } /* try to persist transaction */ var result = _transactionExecuter.Execute(block, receipt, snapshot); if (result != OperatingError.Ok) { OnTransactionFailed?.Invoke(this, receipt); return(result); } /* finalize transaction state */ OnTransactionExecuted?.Invoke(this, receipt); return(OperatingError.Ok); }