Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
 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);
 }
Ejemplo n.º 3
0
        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)));
        }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 5
0
 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;
 }
Ejemplo n.º 6
0
        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));
        }
Ejemplo n.º 7
0
        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);
        }
Ejemplo n.º 8
0
        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));
            }
        }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        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);
        }
Ejemplo n.º 11
0
        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)
                       ));
        }
Ejemplo n.º 12
0
 public InvocationContext(UInt160 sender, IBlockchainSnapshot snapshot, TransactionReceipt receipt)
 {
     Sender   = sender;
     Snapshot = snapshot;
     Receipt  = receipt;
 }
Ejemplo n.º 13
0
 private OperatingError _CheckTransactionGasPrice(Transaction transaction, IBlockchainSnapshot snapshot)
 {
     return(transaction.GasPrice >= snapshot.NetworkGasPrice || transaction.From.IsZero()
         ? OperatingError.Ok
         : OperatingError.Underpriced);
 }
Ejemplo n.º 14
0
        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);
        }