예제 #1
0
        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);
                }
            }
        }
예제 #2
0
        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");
        }
예제 #3
0
        private void Create()
        {
            if (!this.deposit.DBManager.DynamicProperties.SupportVM())
            {
                throw new ContractValidateException("vm work is off, need to be opened by the committee");
            }

            CreateSmartContract contract = ContractCapsule.GetSmartContractFromTransaction(this.transaction);

            if (contract == null)
            {
                throw new ContractValidateException("Cannot get CreateSmartContract from transaction");
            }

            SmartContract new_contract = contract.NewContract;

            if (!contract.OwnerAddress.Equals(new_contract.OriginAddress))
            {
                Logger.Info("OwnerAddress not equals OriginAddress");
                throw new VMIllegalException("OwnerAddress is not equals OriginAddress");
            }

            byte[] contract_name = Encoding.UTF8.GetBytes(new_contract.Name);

            if (contract_name.Length > VMParameter.CONTRACT_NAME_LENGTH)
            {
                throw new ContractValidateException("contractName's length cannot be greater than 32");
            }

            long percent = contract.NewContract.ConsumeUserResourcePercent;

            if (percent < 0 || percent > DefineParameter.ONE_HUNDRED)
            {
                throw new ContractValidateException("percent must be >= 0 and <= 100");
            }

            byte[] contract_address = Wallet.GenerateContractAddress(this.transaction);
            if (this.deposit.GetAccount(contract_address) != null)
            {
                throw new ContractValidateException(
                          "Trying to create a contract with existing contract address: " + Wallet.AddressToBase58(contract_address));
            }

            new_contract.ContractAddress = ByteString.CopyFrom(contract_address);

            long call_value  = new_contract.CallValue;
            long token_value = 0;
            long token_id    = 0;

            if (VMConfig.AllowTvmTransferTrc10)
            {
                token_value = contract.CallTokenValue;
                token_id    = contract.TokenId;
            }

            byte[] caller_address = contract.OwnerAddress.ToByteArray();
            try
            {
                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 creator      = this.deposit.GetAccount(new_contract.OriginAddress.ToByteArray());
                long           energy_limit = 0;
                if (VMConfig.EnergyLimitHardFork)
                {
                    if (call_value < 0)
                    {
                        throw new ContractValidateException("callValue must >= 0");
                    }
                    if (token_value < 0)
                    {
                        throw new ContractValidateException("tokenValue must >= 0");
                    }
                    if (new_contract.OriginEnergyLimit <= 0)
                    {
                        throw new ContractValidateException("The originEnergyLimit must be > 0");
                    }
                    energy_limit = GetAccountEnergyLimitWithFixRatio(creator, fee_limit, call_value);
                }
                else
                {
                    energy_limit = GetAccountEnergyLimitWithFloatRatio(creator, fee_limit, call_value);
                }

                CheckTokenValueAndId(token_value, token_id);

                byte[] ops = new_contract.Bytecode.ToByteArray();
                this.root_internal_transaction = new InternalTransaction(this.transaction, this.transaction_type);

                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_CREATION_TYPE,
                                                                                this.executor_type,
                                                                                this.transaction,
                                                                                token_value,
                                                                                token_id,
                                                                                this.block.Instance,
                                                                                this.deposit,
                                                                                vm_start,
                                                                                vm_should_end,
                                                                                energy_limit);

                this.vm      = new Vm();
                this.program = new Program(ops, 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 (this.enable_listener
                //    && (EventPluginLoader.getInstance().isContractEventTriggerEnable()
                //    || EventPluginLoader.getInstance().isContractLogTriggerEnable())
                //    && IsCheckTransaction)
                //{
                //    logInfoTriggerParser = new LogInfoTriggerParser(this.block.getNum(), this.block.getTimeStamp(), txId, callerAddress);
                //}
            }
            catch (Exception e)
            {
                Logger.Info(e.Message);
                throw new ContractValidateException(e.Message);
            }
            this.program.Result.ContractAddress = contract_address;
            this.deposit.CreateAccount(contract_address, new_contract.Name, AccountType.Contract);
            this.deposit.CreateContract(contract_address, new ContractCapsule(new_contract));
            byte[] code = new_contract.Bytecode.ToByteArray();

            if (!VMConfig.AllowTvmConstantinople)
            {
                deposit.SaveCode(contract_address, ProgramPrecompile.GetCode(code));
            }

            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);
                }
            }
        }
예제 #4
0
 public void UpdateContract(byte[] address, ContractCapsule contract)
 {
     this.contract_cache.Put(new Key(address), Value.Create(contract.Data, ValueType.VALUE_TYPE_DIRTY));
 }
예제 #5
0
 public void CreateContract(byte[] address, ContractCapsule contract)
 {
     this.contract_cache.Add(new Key(address), Value.Create(contract.Data, ValueType.VALUE_TYPE_CREATE));
 }
예제 #6
0
 public void CreateContract(byte[] address, ContractCapsule contract)
 {
     this.deposit.CreateContract(address, contract);
 }
예제 #7
0
        public override bool Validate()
        {
            if (this.contract == null)
            {
                throw new ContractValidateException("No contract!");
            }
            if (this.db_manager == null)
            {
                throw new ContractValidateException("No db_manager!");
            }
            if (this.contract.Is(UpdateSettingContract.Descriptor))
            {
                UpdateSettingContract contract = null;

                try
                {
                    contract = this.contract.Unpack <UpdateSettingContract>();
                }
                catch (InvalidProtocolBufferException e)
                {
                    Logger.Debug(e.Message);
                    throw new ContractValidateException(e.Message);
                }

                if (!Wallet.IsValidAddress(contract.OwnerAddress.ToByteArray()))
                {
                    throw new ContractValidateException("Invalid address");
                }

                byte[] owner_address = contract.OwnerAddress.ToByteArray();

                AccountCapsule account = this.db_manager.Account.Get(owner_address);
                if (account == null)
                {
                    throw new ContractValidateException(
                              "Account[" + owner_address.ToHexString() + "] not exists");
                }

                long new_percent = contract.ConsumeUserResourcePercent;
                if (new_percent > 100 || new_percent < 0)
                {
                    throw new ContractValidateException("percent not in [0, 100]");
                }

                byte[]          contractAddress   = contract.ContractAddress.ToByteArray();
                ContractCapsule deployed_contract = this.db_manager.Contract.Get(contractAddress);

                if (deployed_contract == null)
                {
                    throw new ContractValidateException("Contract not exists");
                }

                byte[] contract_owner_address = deployed_contract.Instance.OriginAddress.ToByteArray();
                if (owner_address.SequenceEqual(contract_owner_address))
                {
                    throw new ContractValidateException(
                              "Account[" + owner_address.ToHexString() + "] is not the owner of the contract");
                }
            }
            else
            {
                throw new ContractValidateException(
                          "contract type error,expected type [UpdateSettingContract],real type[" + contract.GetType().Name + "]");
            }

            return(true);
        }
예제 #8
0
        public List <ContractTrigger> ParseLogInfos(List <LogInfo> log_infos, IDeposit deposit)
        {
            List <ContractTrigger> triggers = new List <ContractTrigger>();

            if (log_infos == null || log_infos.Count <= 0)
            {
                return(triggers);
            }

            Dictionary <string, string> signs = new Dictionary <string, string>();
            Dictionary <string, string> abis  = new Dictionary <string, string>();

            foreach (LogInfo info in log_infos)
            {
                byte[] contract_address     = Wallet.ToAddAddressPrefix(info.Address);
                string contract_address_str = contract_address.IsNotNullOrEmpty() ?
                                              Wallet.AddressToBase58(contract_address) : "";


                if (signs.TryGetValue(contract_address_str, out _) == false)
                {
                    continue;
                }

                ContractCapsule contract = deposit.GetContract(contract_address);
                if (contract == null)
                {
                    signs.Add(contract_address_str, origin_address);
                    abis.Add(contract_address_str, "");
                    continue;
                }

                ABI    abi             = contract.Instance.Abi;
                string creator_address = Wallet.AddressToBase58(Wallet.ToAddAddressPrefix(contract.Instance.OriginAddress.ToByteArray()));
                signs.Add(contract_address_str, creator_address);

                if (abi != null && abi.Entrys.Count > 0)
                {
                    abis.Add(contract_address_str, JsonFormat.PrintToString(abi, false));
                }
                else
                {
                    abis.Add(contract_address_str, "");
                }
            }

            int index = 1;

            foreach (LogInfo info in log_infos)
            {
                byte[] contract_address     = Wallet.ToAddAddressPrefix(info.Address);
                string contract_address_str = contract_address.IsNotNullOrEmpty() ? Wallet.AddressToBase58(contract_address) : "";

                string          abi_value       = abis[contract_address_str];
                ContractTrigger trigger         = new ContractTrigger();
                string          creator_address = signs[contract_address_str];

                trigger.UniqueId        = this.transaction_id + "_" + index;
                trigger.TransactionId   = this.transaction_id;
                trigger.ContractAddress = contract_address_str;
                trigger.OriginAddress   = this.origin_address;
                trigger.CallerAddress   = "";
                trigger.CreatorAddress  = creator_address.IsNotNullOrEmpty() ? creator_address : "";
                trigger.BlockNumber     = this.block_num;
                trigger.Timestamp       = this.block_timestamp;
                trigger.LogInfo         = info;
                trigger.AbiString       = abi_value;

                triggers.Add(trigger);
                index++;
            }

            return(triggers);
        }