public void CheckIsConstant() { if (VMConfig.AllowTvmConstantinople) { return; } TriggerSmartContract trigger_contract = ContractCapsule.GetTriggerContractFromTransaction(this.Transaction.Instance); if (this.transaction_type == TransactionType.TX_CONTRACT_CALL_TYPE) { Deposit deposit = Deposit.CreateRoot(this.db_manager); ContractCapsule contract = deposit.GetContract(trigger_contract.ContractAddress.ToByteArray()); if (contract == null) { Logger.Info(string.Format("contract: {0} is not in contract store", Wallet.AddressToBase58(trigger_contract.ContractAddress.ToByteArray()))); throw new ContractValidateException("contract: " + Wallet.AddressToBase58(trigger_contract.ContractAddress.ToByteArray()) + " is not in contract store"); } ABI abi = contract.Instance.Abi; if (Wallet.IsConstant(abi, trigger_contract)) { throw new VMIllegalException("cannot call constant method"); } } }
private long GetTotalEnergyLimitWithFloatRatio(AccountCapsule creator, AccountCapsule caller, TriggerSmartContract trigger_contract, long fee_limit, long call_value) { long caller_energy_limit = GetAccountEnergyLimitWithFloatRatio(caller, fee_limit, call_value); if (creator.Address.ToByteArray().SequenceEqual(caller.Address.ToByteArray())) { return(caller_energy_limit); } long creator_energy_limit = this.energy_processor.GetAccountLeftEnergyFromFreeze(creator); ContractCapsule contractCapsule = this.deposit.GetContract(trigger_contract.ContractAddress.ToByteArray()); long consume_resource_percent = contractCapsule.GetConsumeUserResourcePercent(); if (creator_energy_limit * consume_resource_percent > (DefineParameter.ONE_HUNDRED - consume_resource_percent) * caller_energy_limit) { return((long)Math.Floor(((double)caller_energy_limit * DefineParameter.ONE_HUNDRED) / consume_resource_percent)); } else { return(caller_energy_limit + creator_energy_limit); } }
public async Task <decimal> BalanceOfAsync(string contractAddress, ITronAccount ownerAccount) { var contractAddressBytes = Base58Encoder.DecodeFromBase58Check(contractAddress); var ownerAddressBytes = Base58Encoder.DecodeFromBase58Check(ownerAccount.Address); var wallet = _walletClient.GetProtocol(); var functionABI = ABITypedRegistry.GetFunctionABI <BalanceOfFunction>(); try { var addressBytes = new byte[20]; Array.Copy(ownerAddressBytes, 1, addressBytes, 0, addressBytes.Length); var addressBytesHex = "0x" + addressBytes.ToHex(); var balanceOf = new BalanceOfFunction { Owner = addressBytesHex }; var decimals = GetDecimals(wallet, contractAddressBytes); var encodedHex = new FunctionCallEncoder().EncodeRequest(balanceOf, functionABI.Sha3Signature); var trigger = new TriggerSmartContract { ContractAddress = ByteString.CopyFrom(contractAddressBytes), OwnerAddress = ByteString.CopyFrom(ownerAddressBytes), Data = ByteString.CopyFrom(encodedHex.HexToByteArray()), }; var transactionExtention = await wallet.TriggerConstantContractAsync(trigger, headers : _walletClient.GetHeaders()); if (!transactionExtention.Result.Result) { throw new Exception(transactionExtention.Result.Message.ToStringUtf8()); } if (transactionExtention.ConstantResult.Count == 0) { throw new Exception($"result error, ConstantResult length=0."); } var result = new FunctionCallDecoder().DecodeFunctionOutput <BalanceOfFunctionOutput>(transactionExtention.ConstantResult[0].ToByteArray().ToHex()); var balance = Convert.ToDecimal(result.Balance); if (decimals > 0) { balance /= Convert.ToDecimal(Math.Pow(10, decimals)); } return(balance); } catch (Exception ex) { _logger.LogError(ex, ex.Message); throw; } }
public long GetTotalEnergyLimit(AccountCapsule creator, AccountCapsule caller, TriggerSmartContract trigger_contract, long fee_limit, long call_value) { if (VMConfig.EnergyLimitHardFork) { return(GetTotalEnergyLimitWithFixRatio(creator, caller, trigger_contract, fee_limit, call_value)); } else { return(GetTotalEnergyLimitWithFloatRatio(creator, caller, trigger_contract, fee_limit, call_value)); } }
public static TriggerSmartContract GetTriggerContractFromTransaction(Transaction tx) { TriggerSmartContract contract = null; try { contract = tx.RawData.Contract[0].Parameter.Unpack <TriggerSmartContract>(); } catch { contract = null; } return(contract); }
public InternalTransaction(Transaction tx, InternalTransaction.TransactionType tx_type) { this.transaction = tx; TransactionCapsule transaction = new TransactionCapsule(tx); this.proto_encoded = transaction.Data; this.nonce = 0; this.deep = -1; if (tx_type == TransactionType.TX_CONTRACT_CREATION_TYPE) { CreateSmartContract contract = ContractCapsule.GetSmartContractFromTransaction(tx); if (contract == null) { throw new ContractValidateException("Invalid CreateSmartContract protocol"); } this.send_address = contract.OwnerAddress.ToByteArray(); this.receive_address = new byte[0]; this.transfer_to_address = Wallet.GenerateContractAddress(tx); this.note = "create"; this.value = contract.NewContract.CallValue; this.data = contract.NewContract.Bytecode.ToByteArray(); this.token_info.Add(contract.TokenId.ToString(), contract.CallTokenValue); } else if (tx_type == TransactionType.TX_CONTRACT_CALL_TYPE) { TriggerSmartContract contract = ContractCapsule.GetTriggerContractFromTransaction(tx); if (contract == null) { throw new ContractValidateException("Invalid TriggerSmartContract protocol"); } this.send_address = contract.OwnerAddress.ToByteArray(); this.receive_address = contract.ContractAddress.ToByteArray(); this.transfer_to_address = (byte[])this.receive_address.Clone(); this.note = "call"; this.value = contract.CallValue; this.data = contract.Data.ToByteArray(); this.token_info.Add(contract.TokenId.ToString(), contract.CallTokenValue); } this.hash = transaction.Id.Hash; }
public long GetTotalEnergyLimitWithFixRatio(AccountCapsule creator, AccountCapsule caller, TriggerSmartContract trigger_contract, long fee_limit, long call_value) { long caller_energy_limit = GetAccountEnergyLimitWithFixRatio(caller, fee_limit, call_value); if (creator.Address.ToByteArray().SequenceEqual(caller.Address.ToByteArray())) { return(caller_energy_limit); } long creator_energy_limit = 0; ContractCapsule contract = this.deposit.GetContract(trigger_contract.ContractAddress.ToByteArray()); long consume_resource_percent = contract.GetConsumeUserResourcePercent(); long origin_energy_limit = contract.GetOriginEnergyLimit(); if (origin_energy_limit < 0) { throw new ContractValidateException("origin_energy_limit can't be < 0"); } if (consume_resource_percent <= 0) { creator_energy_limit = Math.Min(this.energy_processor.GetAccountLeftEnergyFromFreeze(creator), origin_energy_limit); } else { if (consume_resource_percent < DefineParameter.ONE_HUNDRED) { BigInteger left = new BigInteger(caller_energy_limit); left = BigInteger.Multiply(left, new BigInteger(DefineParameter.ONE_HUNDRED - consume_resource_percent)); left = BigInteger.Divide(left, new BigInteger(consume_resource_percent)); long right = Math.Min(this.energy_processor.GetAccountLeftEnergyFromFreeze(creator), origin_energy_limit); creator_energy_limit = Math.Min((long)left, right); } } return(caller_energy_limit + creator_energy_limit); }
public void Pay() { byte[] origin_account = null; byte[] caller_account = null; long percent = 0; long origin_energy_limit = 0; switch (this.transaction_type) { case TransactionType.TX_CONTRACT_CREATION_TYPE: { caller_account = TransactionCapsule.GetOwner(this.transaction.Instance.RawData.Contract[0]); origin_account = caller_account; } break; case TransactionType.TX_CONTRACT_CALL_TYPE: { TriggerSmartContract trigger_contract = ContractCapsule.GetTriggerContractFromTransaction(this.transaction.Instance); ContractCapsule contract = this.db_manager.Contract.Get(trigger_contract.ContractAddress.ToByteArray()); caller_account = trigger_contract.OwnerAddress.ToByteArray(); origin_account = contract.OriginAddress; percent = Math.Max(DefineParameter.ONE_HUNDRED - contract.GetConsumeUserResourcePercent(), 0); percent = Math.Min(percent, DefineParameter.ONE_HUNDRED); origin_energy_limit = contract.GetOriginEnergyLimit(); } break; default: return; } this.receipt.PayEnergyBill(this.db_manager, this.db_manager.Account.Get(origin_account), this.db_manager.Account.Get(caller_account), percent, origin_energy_limit, energy_processor, this.db_manager.WitnessController.GetHeadSlot()); }
private long GetDecimals(Wallet.WalletClient wallet, byte[] contractAddressBytes) { var trc20Decimals = new DecimalsFunction(); var callEncoder = new FunctionCallEncoder(); var functionABI = ABITypedRegistry.GetFunctionABI <DecimalsFunction>(); var encodedHex = callEncoder.EncodeRequest(trc20Decimals, functionABI.Sha3Signature); var trigger = new TriggerSmartContract { ContractAddress = ByteString.CopyFrom(contractAddressBytes), Data = ByteString.CopyFrom(encodedHex.HexToByteArray()), }; var txnExt = wallet.TriggerConstantContract(trigger, headers: _walletClient.GetHeaders()); var result = txnExt.ConstantResult[0].ToByteArray().ToHex(); return(new FunctionCallDecoder().DecodeOutput <long>(result, new Parameter("uint8", "d"))); }
public static bool IsConstant(ABI abi, TriggerSmartContract trigger_contract) { try { bool constant = IsConstant(abi, GetSelector(trigger_contract.Data.ToByteArray())); if (constant) { if (Args.Instance.VM.SupportConstant == false) { throw new ContractValidateException("this node don't support constant"); } } return(constant); } catch (ContractValidateException e) { throw e; } catch { return(false); } }
private void Call() { if (!this.deposit.DBManager.DynamicProperties.SupportVM()) { Logger.Info("vm work is off, need to be opened by the committee"); throw new ContractValidateException("VM work is off, need to be opened by the committee"); } TriggerSmartContract contract = ContractCapsule.GetTriggerContractFromTransaction(this.transaction); if (contract == null) { return; } if (contract.ContractAddress == null) { throw new ContractValidateException("Cannot get contract address from TriggerContract"); } byte[] contract_address = contract.ContractAddress.ToByteArray(); ContractCapsule deployed_contract = this.deposit.GetContract(contract_address); if (null == deployed_contract) { Logger.Info("No contract or not a smart contract"); throw new ContractValidateException("No contract or not a smart contract"); } long call_value = contract.CallValue; long token_value = 0; long token_id = 0; if (VMConfig.AllowTvmTransferTrc10) { token_value = contract.CallTokenValue; token_id = contract.TokenId; } if (VMConfig.EnergyLimitHardFork) { if (call_value < 0) { throw new ContractValidateException("callValue must >= 0"); } if (token_value < 0) { throw new ContractValidateException("tokenValue must >= 0"); } } byte[] caller_address = contract.OwnerAddress.ToByteArray(); CheckTokenValueAndId(token_value, token_id); byte[] code = this.deposit.GetCode(contract_address); if (code != null && code.Length > 0) { long fee_limit = this.transaction.RawData.FeeLimit; if (fee_limit < 0 || fee_limit > VMConfig.MAX_FEE_LIMIT) { Logger.Info(string.Format("invalid feeLimit {0}", fee_limit)); throw new ContractValidateException( "feeLimit must be >= 0 and <= " + VMConfig.MAX_FEE_LIMIT); } AccountCapsule caller = this.deposit.GetAccount(caller_address); long energy_limit = 0; if (this.is_static_call) { energy_limit = DefineParameter.ENERGY_LIMIT_IN_CONSTANT_TX; } else { AccountCapsule creator = this.deposit.GetAccount(deployed_contract.Instance.OriginAddress.ToByteArray()); energy_limit = GetTotalEnergyLimit(creator, caller, contract, fee_limit, call_value); } long max_cpu_time_tx = this.deposit.DBManager.DynamicProperties.GetMaxCpuTimeOfOneTx() * DefineParameter.ONE_THOUSAND; long tx_cpu_limit = (long)(max_cpu_time_tx * GetCpuLimitInUsRatio()); long vm_start = Helper.NanoTime() / DefineParameter.ONE_THOUSAND; long vm_should_end = vm_start + tx_cpu_limit; IProgramInvoke invoke = this.invoke_factory.CreateProgramInvoke(TransactionType.TX_CONTRACT_CALL_TYPE, this.executor_type, this.transaction, token_value, token_id, this.block.Instance, this.deposit, vm_start, vm_should_end, energy_limit); if (this.is_static_call) { invoke.IsStaticCall = true; } this.vm = new Vm(); this.root_internal_transaction = new InternalTransaction(this.transaction, this.transaction_type); this.program = new Program(code, invoke, this.root_internal_transaction, this.block); byte[] tx_id = new TransactionCapsule(this.transaction).Id.Hash; this.program.RootTransactionId = tx_id; // // TODO: EventPluginLoader is not Implementation //if (enableEventLinstener && // (EventPluginLoader.getInstance().isContractEventTriggerEnable() // || EventPluginLoader.getInstance().isContractLogTriggerEnable()) // && isCheckTransaction()) //{ // logInfoTriggerParser = new LogInfoTriggerParser(this.block.getNum(), this.block.getTimeStamp(), txId, callerAddress); //} } this.program.Result.ContractAddress = contract_address; if (call_value > 0) { MUtil.Transfer(this.deposit, caller_address, contract_address, call_value); } if (VMConfig.AllowTvmTransferTrc10) { if (token_value > 0) { MUtil.TransferToken(this.deposit, caller_address, contract_address, token_id.ToString(), token_value); } } }
public IProgramInvoke CreateProgramInvoke(TransactionType tx_type, ExecutorType executor_type, Transaction tx, long token_value, long token_id, Block block, IDeposit deposit, long vm_start, long vm_should_end, long energy_limit) { byte[] data = null; byte[] last_hash = null; byte[] coinbase = null; byte[] contract_address = null; byte[] owner_address = null; long balance = 0; long number = -1; long timestamp = 0; if (tx_type == TransactionType.TX_CONTRACT_CREATION_TYPE) { CreateSmartContract contract = ContractCapsule.GetSmartContractFromTransaction(tx); contract_address = Wallet.GenerateContractAddress(tx); owner_address = contract.OwnerAddress.ToByteArray(); balance = deposit.GetBalance(owner_address); data = new byte[0]; long call_value = contract.NewContract.CallValue; switch (executor_type) { case ExecutorType.ET_NORMAL_TYPE: case ExecutorType.ET_PRE_TYPE: { if (null != block) { last_hash = block.BlockHeader.RawData.ParentHash.ToByteArray(); coinbase = block.BlockHeader.RawData.WitnessAddress.ToByteArray(); timestamp = block.BlockHeader.RawData.Timestamp / 1000; number = block.BlockHeader.RawData.Number; } } break; default: break; } return(new ProgramInvoke(contract_address, owner_address, owner_address, balance, call_value, token_value, token_id, data, last_hash, coinbase, timestamp, number, deposit, vm_start, vm_should_end, energy_limit)); } else if (tx_type == TransactionType.TX_CONTRACT_CALL_TYPE) { TriggerSmartContract contract = ContractCapsule.GetTriggerContractFromTransaction(tx); byte[] address = contract.ContractAddress.ToByteArray(); byte[] origin = contract.OwnerAddress.ToByteArray(); byte[] caller = contract.OwnerAddress.ToByteArray(); balance = deposit.GetBalance(caller); long call_value = contract.CallValue; data = contract.Data.ToByteArray(); switch (executor_type) { case ExecutorType.ET_CONSTANT_TYPE: break; case ExecutorType.ET_PRE_TYPE: case ExecutorType.ET_NORMAL_TYPE: if (null != block) { last_hash = block.BlockHeader.RawData.ParentHash.ToByteArray(); coinbase = block.BlockHeader.RawData.WitnessAddress.ToByteArray(); timestamp = block.BlockHeader.RawData.Timestamp / 1000; number = block.BlockHeader.RawData.Number; } break; default: break; } return(new ProgramInvoke(address, origin, caller, balance, call_value, token_value, token_id, data, last_hash, coinbase, timestamp, number, deposit, vm_start, vm_should_end, energy_limit)); } throw new ContractValidateException("Unknown contract type"); }
public async Task <string> TransferAsync(string contractAddress, ITronAccount ownerAccount, string toAddress, decimal amount, string memo, long feeLimit) { var contractAddressBytes = Base58Encoder.DecodeFromBase58Check(contractAddress); var callerAddressBytes = Base58Encoder.DecodeFromBase58Check(toAddress); var ownerAddressBytes = Base58Encoder.DecodeFromBase58Check(ownerAccount.Address); var wallet = _walletClient.GetProtocol(); var functionABI = ABITypedRegistry.GetFunctionABI <TransferFunction>(); try { var contract = await wallet.GetContractAsync(new BytesMessage { Value = ByteString.CopyFrom(contractAddressBytes), }, headers : _walletClient.GetHeaders()); var toAddressBytes = new byte[20]; Array.Copy(callerAddressBytes, 1, toAddressBytes, 0, toAddressBytes.Length); var toAddressHex = "0x" + toAddressBytes.ToHex(); var decimals = GetDecimals(wallet, contractAddressBytes); var tokenAmount = amount; if (decimals > 0) { tokenAmount = amount * Convert.ToDecimal(Math.Pow(10, decimals)); } var trc20Transfer = new TransferFunction { To = toAddressHex, TokenAmount = Convert.ToInt64(tokenAmount), }; var encodedHex = new FunctionCallEncoder().EncodeRequest(trc20Transfer, functionABI.Sha3Signature); var trigger = new TriggerSmartContract { ContractAddress = ByteString.CopyFrom(contractAddressBytes), OwnerAddress = ByteString.CopyFrom(ownerAddressBytes), Data = ByteString.CopyFrom(encodedHex.HexToByteArray()), }; var transactionExtention = await wallet.TriggerConstantContractAsync(trigger, headers : _walletClient.GetHeaders()); if (!transactionExtention.Result.Result) { _logger.LogWarning($"[transfer]transfer failed, message={transactionExtention.Result.Message.ToStringUtf8()}."); return(null); } var transaction = transactionExtention.Transaction; if (transaction.Ret.Count > 0 && transaction.Ret[0].Ret == Transaction.Types.Result.Types.code.Failed) { return(null); } transaction.RawData.Data = ByteString.CopyFromUtf8(memo); transaction.RawData.FeeLimit = feeLimit; var transSign = _transactionClient.GetTransactionSign(transaction, ownerAccount.PrivateKey); var result = await _transactionClient.BroadcastTransactionAsync(transSign); return(transSign.GetTxid()); } catch (Exception ex) { _logger.LogError(ex, ex.Message); return(null); } }