private void PayTransactionFee(TotalResourceTokensMaps billMaps, bool isMainChain) { foreach (var bill in billMaps.Value) { foreach (var feeMap in bill.TokensMap.Value) { if (feeMap.Value > 0) { ModifyBalance(bill.ContractAddress, feeMap.Key, -feeMap.Value); if (isMainChain) { Context.LogDebug(() => $"Adding {feeMap.Value} of {feeMap.Key}s to dividend pool."); // Main Chain. ModifyBalance(Context.Self, feeMap.Key, feeMap.Value); State.TreasuryContract.Donate.Send(new DonateInput { Symbol = feeMap.Key, Amount = feeMap.Value }); } else { Context.LogDebug(() => $"Adding {feeMap.Value} of {feeMap.Key}s to consensus address account."); // Side Chain var consensusContractAddress = Context.GetContractAddressByName(SmartContractConstants.ConsensusContractSystemName); ModifyBalance(consensusContractAddress, feeMap.Key, feeMap.Value); } } } } }
public override Empty DonateResourceToken(TotalResourceTokensMaps input) { Context.LogDebug(() => $"Start donate resource token. {input}"); State.LatestTotalResourceTokensMapsHash.Value = Hash.FromMessage(input); var isMainChain = true; if (State.TreasuryContract.Value == null) { var treasuryContractAddress = Context.GetContractAddressByName(SmartContractConstants.TreasuryContractSystemName); if (treasuryContractAddress == null) { isMainChain = false; } else { State.TreasuryContract.Value = treasuryContractAddress; } } PayTransactionFee(input, isMainChain); if (!isMainChain) { PayRental(); } return(new Empty()); }
public async Task <List <Transaction> > GenerateTransactionsAsync(Address @from, long preBlockHeight, Hash preBlockHash) { var generatedTransactions = new List <Transaction>(); var chainContext = new ChainContext { BlockHash = preBlockHash, BlockHeight = preBlockHeight }; var tokenContractAddress = await _smartContractAddressService.GetAddressByContractNameAsync(chainContext, TokenSmartContractAddressNameProvider.StringName); if (tokenContractAddress == null) { return(generatedTransactions); } var totalResourceTokensMaps = await _totalResourceTokensMapsProvider.GetTotalResourceTokensMapsAsync( chainContext); ByteString input; if (totalResourceTokensMaps != null && totalResourceTokensMaps.BlockHeight == preBlockHeight && totalResourceTokensMaps.BlockHash == preBlockHash) { // If totalResourceTokensMaps match current block. input = totalResourceTokensMaps.ToByteString(); } else { input = new TotalResourceTokensMaps { BlockHash = preBlockHash, BlockHeight = preBlockHeight }.ToByteString(); } generatedTransactions.AddRange(new List <Transaction> { new Transaction { From = from, MethodName = nameof(TokenContractImplContainer.TokenContractImplStub.DonateResourceToken), To = tokenContractAddress, RefBlockNumber = preBlockHeight, RefBlockPrefix = BlockHelper.GetRefBlockPrefix(preBlockHash), Params = input } }); Logger.LogTrace("Tx DonateResourceToken generated."); return(generatedTransactions); }
public override async Task ProcessAsync(Block block, Dictionary <TransactionResult, List <LogEvent> > logEventsMap) { var blockHash = block.GetHash(); var blockHeight = block.Height; var totalResourceTokensMaps = new TotalResourceTokensMaps { BlockHash = blockHash, BlockHeight = blockHeight }; foreach (var logEvent in logEventsMap.Values.SelectMany(logEvents => logEvents)) { var eventData = new ResourceTokenCharged(); eventData.MergeFrom(logEvent); if (eventData.Symbol == null || eventData.Amount == 0) { continue; } if (totalResourceTokensMaps.Value.Any(b => b.ContractAddress == eventData.ContractAddress)) { var oldBill = totalResourceTokensMaps.Value.First(b => b.ContractAddress == eventData.ContractAddress); if (oldBill.TokensMap.Value.ContainsKey(eventData.Symbol)) { oldBill.TokensMap.Value[eventData.Symbol] += eventData.Amount; } else { oldBill.TokensMap.Value.Add(eventData.Symbol, eventData.Amount); } } else { var contractTotalResourceTokens = new ContractTotalResourceTokens { ContractAddress = eventData.ContractAddress, TokensMap = new TotalResourceTokensMap { Value = { { eventData.Symbol, eventData.Amount } } } }; totalResourceTokensMaps.Value.Add(contractTotalResourceTokens); } } await _totalTotalResourceTokensMapsProvider.SetTotalResourceTokensMapsAsync(new BlockIndex { BlockHash = blockHash, BlockHeight = blockHeight }, totalResourceTokensMaps); }
private void PayResourceTokens(TotalResourceTokensMaps billMaps, bool isMainChain) { foreach (var bill in billMaps.Value) { foreach (var feeMap in bill.TokensMap.Value) { var symbol = feeMap.Key; var amount = feeMap.Value; // Check balance in case of insufficient balance. var existingBalance = GetBalance(bill.ContractAddress, symbol); if (amount > existingBalance) { var owned = amount.Sub(existingBalance); var currentOwning = State.OwningResourceToken[bill.ContractAddress][symbol].Add(owned); State.OwningResourceToken[bill.ContractAddress][symbol] = currentOwning; Context.Fire(new ResourceTokenOwned { Symbol = symbol, Amount = currentOwning, ContractAddress = bill.ContractAddress }); amount = existingBalance; } if (amount > 0) { ModifyBalance(bill.ContractAddress, symbol, -amount); if (isMainChain) { Context.LogDebug(() => $"Adding {amount} of {symbol}s to dividend pool."); // Main Chain. ModifyBalance(Context.Self, symbol, amount); State.DividendPoolContract.Donate.Send(new DonateInput { Symbol = symbol, Amount = amount }); } else { Context.LogDebug(() => $"Adding {amount} of {symbol}s to consensus address account."); // Side Chain var consensusContractAddress = Context.GetContractAddressByName(SmartContractConstants.ConsensusContractSystemName); ModifyBalance(consensusContractAddress, symbol, amount); } } } } }
public async Task DonateResourceToken_Test(long[] initialBalances, long[] tokenFee, long[] lastBalances, bool isMainChain) { var symbolList = new [] { "WEO", "CWJ", "YPA" }; var feeMap = new TotalResourceTokensMaps(); for (var i = 0; i < symbolList.Length; i++) { await CreateTokenAsync(DefaultSender, symbolList[i]); await IssueTokenAsync(symbolList[i], initialBalances[i]); feeMap.Value.Add(new ContractTotalResourceTokens { ContractAddress = DefaultSender, TokensMap = new TotalResourceTokensMap { Value = { { symbolList[i], tokenFee[i] } } } }); } if (!isMainChain) { var defaultParliament = await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty()); await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress, nameof(TokenContractContainer.TokenContractStub.InitializeFromParentChain), new InitializeFromParentChainInput { Creator = defaultParliament }); } await TokenContractStub.DonateResourceToken.SendAsync(feeMap); for (var i = 0; i < symbolList.Length; i++) { var balance = await GetBalanceAsync(DefaultSender, symbolList[i]); balance.ShouldBe(lastBalances[i]); if (!isMainChain) { var consensusBalance = await GetBalanceAsync(ConsensusContractAddress, symbolList[i]); consensusBalance.ShouldBe(initialBalances[i] - lastBalances[i]); } } }
public override Empty DonateResourceToken(TotalResourceTokensMaps input) { AssertSenderIsCurrentMiner(); var donateResourceTokenExecuteHeight = State.DonateResourceTokenExecuteHeight.Value; if (donateResourceTokenExecuteHeight == 0) { donateResourceTokenExecuteHeight = Context.CurrentHeight; } Assert(donateResourceTokenExecuteHeight == Context.CurrentHeight, $"This method already executed in height {State.DonateResourceTokenExecuteHeight.Value}"); State.DonateResourceTokenExecuteHeight.Value = donateResourceTokenExecuteHeight.Add(1); Context.LogDebug(() => $"Start donate resource token. {input}"); State.LatestTotalResourceTokensMapsHash.Value = HashHelper.ComputeFrom(input); Context.LogDebug(() => $"Now LatestTotalResourceTokensMapsHash is {State.LatestTotalResourceTokensMapsHash.Value}"); var isMainChain = true; if (State.DividendPoolContract.Value == null) { var treasuryContractAddress = Context.GetContractAddressByName(SmartContractConstants.TreasuryContractSystemName); if (treasuryContractAddress == null) { isMainChain = false; } else { State.DividendPoolContract.Value = treasuryContractAddress; } } PayResourceTokens(input, isMainChain); if (!isMainChain) { PayRental(); } return(new Empty()); }
public async Task ProcessAsync(Block block, TransactionResult transactionResult, LogEvent logEvent) { var eventData = new ResourceTokenCharged(); eventData.MergeFrom(logEvent); if (eventData.Symbol == null || eventData.Amount == 0) { return; } var blockHash = block.GetHash(); var blockHeight = block.Height; // TODO: Get -> Modify -> Set is slow, consider collect all logEvents then generate the totalResourceTokensMap at once. var totalResourceTokensMaps = await _totalTotalResourceTokensMapsProvider.GetTotalResourceTokensMapsAsync( new ChainContext { BlockHash = block.GetHash(), BlockHeight = block.Height, }); // Initial totalTxFeesMap if necessary (either never initialized or not initialized for current block link) if (totalResourceTokensMaps == null) { totalResourceTokensMaps = new TotalResourceTokensMaps { BlockHash = blockHash, BlockHeight = blockHeight }; } else if (totalResourceTokensMaps.BlockHash != blockHash || totalResourceTokensMaps.BlockHeight != blockHeight) { totalResourceTokensMaps = new TotalResourceTokensMaps { BlockHash = blockHash, BlockHeight = blockHeight }; } if (totalResourceTokensMaps.Value.Any() && totalResourceTokensMaps.Value.Any(b => b.ContractAddress == eventData.ContractAddress)) { var oldBill = totalResourceTokensMaps.Value.First(b => b.ContractAddress == eventData.ContractAddress); if (oldBill.TokensMap.Value.ContainsKey(eventData.Symbol)) { oldBill.TokensMap.Value[eventData.Symbol] += eventData.Amount; } else { oldBill.TokensMap.Value.Add(eventData.Symbol, eventData.Amount); } } else { var contractTotalResourceTokens = new ContractTotalResourceTokens { ContractAddress = eventData.ContractAddress, TokensMap = new TotalResourceTokensMap { Value = { { eventData.Symbol, eventData.Amount } } } }; totalResourceTokensMaps.Value.Add(contractTotalResourceTokens); } await _totalTotalResourceTokensMapsProvider.SetTotalResourceTokensMapsAsync(new BlockIndex { BlockHash = blockHash, BlockHeight = blockHeight }, totalResourceTokensMaps); }