diff --git a/AElf.All.sln b/AElf.All.sln
index 7554592ce4..b95c9f20ab 100644
--- a/AElf.All.sln
+++ b/AElf.All.sln
@@ -369,6 +369,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.CSharp.CodeOps.UnitTes
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Kernel.SmartContract.ExecutionPluginForUserContractFee.Tests.TestContract", "test\AElf.Kernel.SmartContract.ExecutionPluginForUserContractFee.Tests.TestContract\AElf.Kernel.SmartContract.ExecutionPluginForUserContractFee.Tests.TestContract.csproj", "{AB27298B-E6BE-4ACB-ADF1-64239E2A7A1C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Contracts.TestContract.Vote", "test\AElf.Contracts.TestContract.Vote\AElf.Contracts.TestContract.Vote.csproj", "{860947CF-F081-4A3B-BE65-199ECE793616}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Contracts.TestContract.MockParliament", "test\AElf.Contracts.TestContract.MockParliament\AElf.Contracts.TestContract.MockParliament.csproj", "{C7EDD0EB-CCE7-4B06-BF1E-F9CA7F149097}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Contracts.TestContract.VirtualAddress", "test\AElf.Contracts.TestContract.VirtualAddress\AElf.Contracts.TestContract.VirtualAddress.csproj", "{64498F8C-B827-4E1C-B5FB-4B9188C839A8}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1059,6 +1065,18 @@ Global
{AB27298B-E6BE-4ACB-ADF1-64239E2A7A1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB27298B-E6BE-4ACB-ADF1-64239E2A7A1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AB27298B-E6BE-4ACB-ADF1-64239E2A7A1C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {860947CF-F081-4A3B-BE65-199ECE793616}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {860947CF-F081-4A3B-BE65-199ECE793616}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {860947CF-F081-4A3B-BE65-199ECE793616}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {860947CF-F081-4A3B-BE65-199ECE793616}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C7EDD0EB-CCE7-4B06-BF1E-F9CA7F149097}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C7EDD0EB-CCE7-4B06-BF1E-F9CA7F149097}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C7EDD0EB-CCE7-4B06-BF1E-F9CA7F149097}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C7EDD0EB-CCE7-4B06-BF1E-F9CA7F149097}.Release|Any CPU.Build.0 = Release|Any CPU
+ {64498F8C-B827-4E1C-B5FB-4B9188C839A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {64498F8C-B827-4E1C-B5FB-4B9188C839A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {64498F8C-B827-4E1C-B5FB-4B9188C839A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {64498F8C-B827-4E1C-B5FB-4B9188C839A8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1245,5 +1263,8 @@ Global
{1B44277E-74EB-49B2-B8FD-05C29EE51985} = {4E54480A-D155-43ED-9736-1A5BE7957211}
{D1A00CD6-958E-4E9F-8325-354309E3029E} = {4E54480A-D155-43ED-9736-1A5BE7957211}
{AB27298B-E6BE-4ACB-ADF1-64239E2A7A1C} = {4E54480A-D155-43ED-9736-1A5BE7957211}
+ {860947CF-F081-4A3B-BE65-199ECE793616} = {D3950CC9-808F-4ED8-946A-79A992F3F8EF}
+ {C7EDD0EB-CCE7-4B06-BF1E-F9CA7F149097} = {D3950CC9-808F-4ED8-946A-79A992F3F8EF}
+ {64498F8C-B827-4E1C-B5FB-4B9188C839A8} = {D3950CC9-808F-4ED8-946A-79A992F3F8EF}
EndGlobalSection
EndGlobal
diff --git a/bench/AElf.Benchmark/VRFTests.cs b/bench/AElf.Benchmark/VRFTests.cs
new file mode 100644
index 0000000000..9dae76aafd
--- /dev/null
+++ b/bench/AElf.Benchmark/VRFTests.cs
@@ -0,0 +1,45 @@
+using System;
+using AElf.Cryptography;
+using AElf.Cryptography.ECDSA;
+using BenchmarkDotNet.Attributes;
+
+namespace AElf.Benchmark;
+
+[MarkdownExporterAttribute.GitHub]
+public class VrfTests : BenchmarkTestBase
+{
+ private ECKeyPair _key;
+ private byte[] _alphaBytes;
+ private byte[] _piBytes;
+
+ [Params(1,10,100,1000)] public int VectorCount;
+
+ [GlobalSetup]
+ public void GlobalSetup()
+ {
+ _key = CryptoHelper.FromPrivateKey(
+ ByteArrayHelper.HexStringToByteArray("2eaeb403475a9962ad59302ab53fa2b668d2d24bf5a2a917707e5b2f4ded392b"));
+ var alpha = "fb779e58991c424eaaf10b3d364c3b3e756c7b435109a985e547c058964d7bd5";
+ _alphaBytes = Convert.FromHexString(alpha);
+ var pi = "03ea6c4bdb4a9e1ae0a17c427ec074f68cdac7a57e4f3fded1b07d20dd5385baf05a9d1e4064cd1c2c5e8608e96b7e3e2058500f178b414b8e910178f17a7a77af7e88befeabceb77cae3e9fd2e1a6c051";
+ _piBytes = Convert.FromHexString(pi);
+ }
+
+ [Benchmark]
+ public void VrfProveTest()
+ {
+ for (var i = 0; i < VectorCount; i++)
+ {
+ CryptoHelper.ECVrfProve(_key, _alphaBytes);
+ }
+ }
+
+ [Benchmark]
+ public void VrfVerifyTest()
+ {
+ for (var i = 0; i < VectorCount; i++)
+ {
+ CryptoHelper.ECVrfVerify(_key.PublicKey, _alphaBytes, _piBytes);
+ }
+ }
+}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract.cs b/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract.cs
index 9517ca71b1..e129ea9236 100644
--- a/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract.cs
+++ b/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract.cs
@@ -158,7 +158,7 @@ public override Empty RecordCandidateReplacement(RecordCandidateReplacementInput
#region NextRound
- public override Empty NextRound(Round input)
+ public override Empty NextRound(NextRoundInput input)
{
SupplyCurrentRoundInformation();
ProcessConsensusInformation(input);
diff --git a/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract_ACS4_ConsensusInformationProvider.cs b/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract_ACS4_ConsensusInformationProvider.cs
index 4bbf853a65..9c059c426b 100644
--- a/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract_ACS4_ConsensusInformationProvider.cs
+++ b/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract_ACS4_ConsensusInformationProvider.cs
@@ -1,5 +1,6 @@
using System.Linq;
using AElf.Standards.ACS4;
+using AElf.Types;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
@@ -66,9 +67,10 @@ public override TransactionList GenerateConsensusTransactions(BytesValue input)
"Data to request consensus information should contain pubkey.");
var pubkey = triggerInformation.Pubkey;
+ var randomNumber = triggerInformation.RandomNumber;
var consensusInformation = new AElfConsensusHeaderInformation();
consensusInformation.MergeFrom(GetConsensusBlockExtraData(input, true).Value);
- var transactionList = GenerateTransactionListByExtraData(consensusInformation, pubkey);
+ var transactionList = GenerateTransactionListByExtraData(consensusInformation, pubkey, randomNumber);
return transactionList;
}
@@ -126,7 +128,7 @@ public override ValidationResult ValidateConsensusAfterExecution(BytesValue inpu
}
private TransactionList GenerateTransactionListByExtraData(AElfConsensusHeaderInformation consensusInformation,
- ByteString pubkey)
+ ByteString pubkey, ByteString randomNumber)
{
var round = consensusInformation.Round;
var behaviour = consensusInformation.Behaviour;
@@ -140,7 +142,7 @@ private TransactionList GenerateTransactionListByExtraData(AElfConsensusHeaderIn
Transactions =
{
GenerateTransaction(nameof(UpdateValue),
- round.ExtractInformationToUpdateConsensus(pubkey.ToHex()))
+ round.ExtractInformationToUpdateConsensus(pubkey.ToHex(), randomNumber))
}
};
case AElfConsensusBehaviour.TinyBlock:
@@ -154,7 +156,8 @@ private TransactionList GenerateTransactionListByExtraData(AElfConsensusHeaderIn
{
ActualMiningTime = minerInRound.ActualMiningTimes.Last(),
ProducedBlocks = minerInRound.ProducedBlocks,
- RoundId = round.RoundIdForValidation
+ RoundId = round.RoundIdForValidation,
+ RandomNumber = randomNumber
})
}
};
@@ -163,7 +166,7 @@ private TransactionList GenerateTransactionListByExtraData(AElfConsensusHeaderIn
{
Transactions =
{
- GenerateTransaction(nameof(NextRound), round)
+ GenerateTransaction(nameof(NextRound), NextRoundInput.Create(round,randomNumber))
}
};
case AElfConsensusBehaviour.NextTerm:
@@ -171,7 +174,7 @@ private TransactionList GenerateTransactionListByExtraData(AElfConsensusHeaderIn
{
Transactions =
{
- GenerateTransaction(nameof(NextTerm), round)
+ GenerateTransaction(nameof(NextTerm), NextTermInput.Create(round,randomNumber))
}
};
default:
diff --git a/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract_NextTerm.cs b/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract_NextTerm.cs
index fbe886f8a4..d6569b7cdd 100644
--- a/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract_NextTerm.cs
+++ b/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract_NextTerm.cs
@@ -10,7 +10,7 @@ namespace AElf.Contracts.Consensus.AEDPoS;
// ReSharper disable once InconsistentNaming
public partial class AEDPoSContract
{
- public override Empty NextTerm(Round input)
+ public override Empty NextTerm(NextTermInput input)
{
SupplyCurrentRoundInformation();
ProcessConsensusInformation(input);
diff --git a/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract_ProcessConsensusInformation.cs b/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract_ProcessConsensusInformation.cs
index 4e37a46580..fd1e42e738 100644
--- a/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract_ProcessConsensusInformation.cs
+++ b/contract/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract_ProcessConsensusInformation.cs
@@ -5,6 +5,7 @@
using AElf.Sdk.CSharp;
using AElf.Standards.ACS10;
using AElf.Types;
+using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
namespace AElf.Contracts.Consensus.AEDPoS;
@@ -28,19 +29,25 @@ private void ProcessConsensusInformation(dynamic input, [CallerMemberName] strin
State.RoundBeforeLatestExecution.Value = GetCurrentRoundInformation(new Empty());
+ ByteString randomNumber = null;
+
// The only difference.
switch (input)
{
- case Round round when callerMethodName == nameof(NextRound):
- ProcessNextRound(round);
+ case NextRoundInput nextRoundInput:
+ randomNumber = nextRoundInput.RandomNumber;
+ ProcessNextRound(nextRoundInput);
break;
- case Round round when callerMethodName == nameof(NextTerm):
- ProcessNextTerm(round);
+ case NextTermInput nextTermInput:
+ randomNumber = nextTermInput.RandomNumber;
+ ProcessNextTerm(nextTermInput);
break;
case UpdateValueInput updateValueInput:
+ randomNumber = updateValueInput.RandomNumber;
ProcessUpdateValue(updateValueInput);
break;
case TinyBlockInput tinyBlockInput:
+ randomNumber = tinyBlockInput.RandomNumber;
ProcessTinyBlock(tinyBlockInput);
break;
}
@@ -65,14 +72,12 @@ private void ProcessConsensusInformation(dynamic input, [CallerMemberName] strin
Context.LogDebug(() =>
$"Current round information:\n{currentRound.ToString(_processingBlockMinerPubkey)}");
- var latestSignature = GetLatestSignature(currentRound);
- var previousRandomHash = State.RandomHashes[Context.CurrentHeight.Sub(1)];
- var randomHash = previousRandomHash == null
- ? latestSignature
- : HashHelper.XorAndCompute(previousRandomHash, latestSignature);
-
+ var previousRandomHash = State.RandomHashes[Context.CurrentHeight.Sub(1)] ?? Hash.Empty;
+ Assert(
+ Context.ECVrfVerify(Context.RecoverPublicKey(), previousRandomHash.ToByteArray(),
+ randomNumber.ToByteArray(), out var beta), "Failed to verify random number.");
+ var randomHash = Hash.LoadFromByteArray(beta);
State.RandomHashes[Context.CurrentHeight] = randomHash;
-
Context.LogDebug(() => $"New random hash generated: {randomHash} - height {Context.CurrentHeight}");
if (!State.IsMainChain.Value && currentRound.RoundNumber > 1) Release();
@@ -100,8 +105,10 @@ private Hash GetLatestSignature(Round currentRound)
return latestSignature;
}
- private void ProcessNextRound(Round nextRound)
+ private void ProcessNextRound(NextRoundInput input)
{
+ var nextRound = input.ToRound();
+
RecordMinedMinerListOfCurrentRound();
TryToGetCurrentRoundInformation(out var currentRound);
@@ -149,8 +156,10 @@ private void ProcessNextRound(Round nextRound)
Assert(TryToUpdateRoundNumber(nextRound.RoundNumber), "Failed to update round number.");
}
- private void ProcessNextTerm(Round nextRound)
+ private void ProcessNextTerm(NextTermInput input)
{
+ var nextRound = input.ToRound();
+
RecordMinedMinerListOfCurrentRound();
// Count missed time slot of current round.
diff --git a/contract/AElf.Contracts.Consensus.AEDPoS/AElf.Contracts.Consensus.AEDPoS.csproj b/contract/AElf.Contracts.Consensus.AEDPoS/AElf.Contracts.Consensus.AEDPoS.csproj
index 13ae50e26c..e197019f68 100644
--- a/contract/AElf.Contracts.Consensus.AEDPoS/AElf.Contracts.Consensus.AEDPoS.csproj
+++ b/contract/AElf.Contracts.Consensus.AEDPoS/AElf.Contracts.Consensus.AEDPoS.csproj
@@ -1,5 +1,5 @@
-
+
net6.0
diff --git a/contract/AElf.Contracts.Consensus.AEDPoS/Types/NextRoundInput.cs b/contract/AElf.Contracts.Consensus.AEDPoS/Types/NextRoundInput.cs
new file mode 100644
index 0000000000..e3240dc417
--- /dev/null
+++ b/contract/AElf.Contracts.Consensus.AEDPoS/Types/NextRoundInput.cs
@@ -0,0 +1,41 @@
+using Google.Protobuf;
+
+namespace AElf.Contracts.Consensus.AEDPoS;
+
+public partial class NextRoundInput
+{
+ public static NextRoundInput Create(Round round, ByteString randomNumber)
+ {
+ return new NextRoundInput
+ {
+ RoundNumber = round.RoundNumber,
+ RealTimeMinersInformation = { round.RealTimeMinersInformation },
+ ExtraBlockProducerOfPreviousRound = round.ExtraBlockProducerOfPreviousRound,
+ BlockchainAge = round.BlockchainAge,
+ TermNumber = round.TermNumber,
+ ConfirmedIrreversibleBlockHeight = round.ConfirmedIrreversibleBlockHeight,
+ ConfirmedIrreversibleBlockRoundNumber = round.ConfirmedIrreversibleBlockRoundNumber,
+ IsMinerListJustChanged = round.IsMinerListJustChanged,
+ RoundIdForValidation = round.RoundIdForValidation,
+ MainChainMinersRoundNumber = round.MainChainMinersRoundNumber,
+ RandomNumber = randomNumber
+ };
+ }
+
+ public Round ToRound()
+ {
+ return new Round
+ {
+ RoundNumber = RoundNumber,
+ RealTimeMinersInformation = { RealTimeMinersInformation },
+ ExtraBlockProducerOfPreviousRound = ExtraBlockProducerOfPreviousRound,
+ BlockchainAge = BlockchainAge,
+ TermNumber = TermNumber,
+ ConfirmedIrreversibleBlockHeight = ConfirmedIrreversibleBlockHeight,
+ ConfirmedIrreversibleBlockRoundNumber = ConfirmedIrreversibleBlockRoundNumber,
+ IsMinerListJustChanged = IsMinerListJustChanged,
+ RoundIdForValidation = RoundIdForValidation,
+ MainChainMinersRoundNumber = MainChainMinersRoundNumber
+ };
+ }
+}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.Consensus.AEDPoS/Types/NextTermInput.cs b/contract/AElf.Contracts.Consensus.AEDPoS/Types/NextTermInput.cs
new file mode 100644
index 0000000000..74afc3daac
--- /dev/null
+++ b/contract/AElf.Contracts.Consensus.AEDPoS/Types/NextTermInput.cs
@@ -0,0 +1,41 @@
+using Google.Protobuf;
+
+namespace AElf.Contracts.Consensus.AEDPoS;
+
+public partial class NextTermInput
+{
+ public static NextTermInput Create(Round round, ByteString randomNumber)
+ {
+ return new NextTermInput
+ {
+ RoundNumber = round.RoundNumber,
+ RealTimeMinersInformation = { round.RealTimeMinersInformation },
+ ExtraBlockProducerOfPreviousRound = round.ExtraBlockProducerOfPreviousRound,
+ BlockchainAge = round.BlockchainAge,
+ TermNumber = round.TermNumber,
+ ConfirmedIrreversibleBlockHeight = round.ConfirmedIrreversibleBlockHeight,
+ ConfirmedIrreversibleBlockRoundNumber = round.ConfirmedIrreversibleBlockRoundNumber,
+ IsMinerListJustChanged = round.IsMinerListJustChanged,
+ RoundIdForValidation = round.RoundIdForValidation,
+ MainChainMinersRoundNumber = round.MainChainMinersRoundNumber,
+ RandomNumber = randomNumber
+ };
+ }
+
+ public Round ToRound()
+ {
+ return new Round
+ {
+ RoundNumber = RoundNumber,
+ RealTimeMinersInformation = { RealTimeMinersInformation },
+ ExtraBlockProducerOfPreviousRound = ExtraBlockProducerOfPreviousRound,
+ BlockchainAge = BlockchainAge,
+ TermNumber = TermNumber,
+ ConfirmedIrreversibleBlockHeight = ConfirmedIrreversibleBlockHeight,
+ ConfirmedIrreversibleBlockRoundNumber = ConfirmedIrreversibleBlockRoundNumber,
+ IsMinerListJustChanged = IsMinerListJustChanged,
+ RoundIdForValidation = RoundIdForValidation,
+ MainChainMinersRoundNumber = MainChainMinersRoundNumber
+ };
+ }
+}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.Consensus.AEDPoS/Types/Round_ExtractInformationToUpdateConsensus.cs b/contract/AElf.Contracts.Consensus.AEDPoS/Types/Round_ExtractInformationToUpdateConsensus.cs
index 786eef5ca0..b0d93721cb 100644
--- a/contract/AElf.Contracts.Consensus.AEDPoS/Types/Round_ExtractInformationToUpdateConsensus.cs
+++ b/contract/AElf.Contracts.Consensus.AEDPoS/Types/Round_ExtractInformationToUpdateConsensus.cs
@@ -1,5 +1,6 @@
using System.Linq;
using AElf.Types;
+using Google.Protobuf;
namespace AElf.Contracts.Consensus.AEDPoS;
@@ -10,8 +11,9 @@ public partial class Round
/// will record this purpose to their FinalOrderOfNextRound field.
///
///
+ ///
///
- public UpdateValueInput ExtractInformationToUpdateConsensus(string pubkey)
+ public UpdateValueInput ExtractInformationToUpdateConsensus(string pubkey, ByteString randomNumber)
{
if (!RealTimeMinersInformation.ContainsKey(pubkey)) return null;
@@ -43,7 +45,8 @@ public UpdateValueInput ExtractInformationToUpdateConsensus(string pubkey)
EncryptedPieces = { minerInRound.EncryptedPieces },
DecryptedPieces = { decryptedPreviousInValues },
MinersPreviousInValues = { minersPreviousInValues },
- ImpliedIrreversibleBlockHeight = minerInRound.ImpliedIrreversibleBlockHeight
+ ImpliedIrreversibleBlockHeight = minerInRound.ImpliedIrreversibleBlockHeight,
+ RandomNumber = randomNumber
};
}
}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.CrossChain/CrossChainContract_Helper.cs b/contract/AElf.Contracts.CrossChain/CrossChainContract_Helper.cs
index 9ae9dac72b..5f01430998 100644
--- a/contract/AElf.Contracts.CrossChain/CrossChainContract_Helper.cs
+++ b/contract/AElf.Contracts.CrossChain/CrossChainContract_Helper.cs
@@ -189,7 +189,8 @@ private void CreateSideChainToken(SideChainCreationRequest sideChainCreationRequ
Issuer = creator,
IssueChainId = chainId,
Symbol = sideChainCreationRequest.SideChainTokenCreationRequest.SideChainTokenSymbol,
- TotalSupply = sideChainCreationRequest.SideChainTokenCreationRequest.SideChainTokenTotalSupply
+ TotalSupply = sideChainCreationRequest.SideChainTokenCreationRequest.SideChainTokenTotalSupply,
+ Owner = creator
});
}
diff --git a/contract/AElf.Contracts.Economic/EconomicContract.cs b/contract/AElf.Contracts.Economic/EconomicContract.cs
index f9c0fbe353..e971433777 100644
--- a/contract/AElf.Contracts.Economic/EconomicContract.cs
+++ b/contract/AElf.Contracts.Economic/EconomicContract.cs
@@ -59,7 +59,8 @@ private void CreateNativeToken(InitialEconomicSystemInput input)
Decimals = input.NativeTokenDecimals,
IsBurnable = input.IsNativeTokenBurnable,
Issuer = Context.Self,
- LockWhiteList = { lockWhiteList }
+ LockWhiteList = { lockWhiteList },
+ Owner = Context.Self
});
State.TokenContract.SetPrimaryTokenSymbol.Send(new SetPrimaryTokenSymbolInput
@@ -88,7 +89,8 @@ private void CreateResourceTokens()
Decimals = EconomicContractConstants.ResourceTokenDecimals,
Issuer = Context.Self,
LockWhiteList = { lockWhiteList },
- IsBurnable = true
+ IsBurnable = true,
+ Owner = Context.Self
});
State.TokenContract.Issue.Send(new IssueInput
@@ -120,7 +122,8 @@ private void CreateElectionTokens()
Decimals = EconomicContractConstants.ElectionTokenDecimals,
Issuer = Context.Self,
IsBurnable = true,
- LockWhiteList = { lockWhiteList }
+ LockWhiteList = { lockWhiteList },
+ Owner = Context.Self
});
State.TokenContract.Issue.Send(new IssueInput
{
diff --git a/contract/AElf.Contracts.Election/ElectionContractState.cs b/contract/AElf.Contracts.Election/ElectionContractState.cs
index 90920ac79d..f9bfd7125e 100644
--- a/contract/AElf.Contracts.Election/ElectionContractState.cs
+++ b/contract/AElf.Contracts.Election/ElectionContractState.cs
@@ -15,6 +15,7 @@ public partial class ElectionContractState : ContractState
public SingletonState FlexibleHash { get; set; }
public SingletonState WelcomeHash { get; set; }
+ // Old:Pubkey/New:Address -> ElectorVote
public MappedState ElectorVotes { get; set; }
public MappedState CandidateVotes { get; set; }
diff --git a/contract/AElf.Contracts.Election/ElectionContract_Elector.cs b/contract/AElf.Contracts.Election/ElectionContract_Elector.cs
index a021802fb6..eaf28224fe 100644
--- a/contract/AElf.Contracts.Election/ElectionContract_Elector.cs
+++ b/contract/AElf.Contracts.Election/ElectionContract_Elector.cs
@@ -3,12 +3,10 @@
using System.Linq;
using AElf.Contracts.MultiToken;
using AElf.Contracts.Profit;
-using AElf.Contracts.Treasury;
using AElf.Contracts.Vote;
using AElf.CSharp.Core;
using AElf.Sdk.CSharp;
using AElf.Types;
-using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
namespace AElf.Contracts.Election;
@@ -129,7 +127,7 @@ private void ExtendVoterWelfareProfits(Hash voteId)
{
var treasury = State.ProfitContract.GetScheme.Call(State.TreasuryHash.Value);
var electionVotingRecord = GetElectionVotingRecordByVoteId(voteId);
-
+
// Extend endPeriod from now no, so the lockTime will *NOT* be changed.
var lockTime = State.LockTimeMap[voteId];
var lockPeriod = lockTime.Div(State.TimeEachTerm.Value);
@@ -182,7 +180,7 @@ private ProfitDetail GetProfitDetailByElectionVotingRecord(ElectionVotingRecord
{
profitDetail = profitDetails.Details.LastOrDefault(d => d.Shares == electionVotingRecord.Weight);
}
-
+
return profitDetail;
}
@@ -326,7 +324,7 @@ private void AssertValidLockSeconds(long lockSeconds)
Assert(lockSeconds <= State.MaximumLockTime.Value,
$"Invalid lock time. At most {State.MaximumLockTime.Value.Div(60).Div(60).Div(24)} days");
}
-
+
private void LockTokensOfVoter(long amount, Hash voteId)
{
State.TokenContract.Lock.Send(new LockInput
@@ -499,14 +497,13 @@ private void TryToBecomeAValidationDataCenter(VoteMinerInput input, long candida
///
private void UpdateElectorInformation(byte[] recoveredPublicKey, long amount, Hash voteId)
{
- var voterPublicKey = recoveredPublicKey.ToHex();
- var voterPublicKeyByteString = ByteString.CopyFrom(recoveredPublicKey);
- var voterVotes = State.ElectorVotes[voterPublicKey];
+ var voterVotes = GetElectorVote(recoveredPublicKey);
+
if (voterVotes == null)
{
voterVotes = new ElectorVote
{
- Pubkey = voterPublicKeyByteString,
+ Address = Context.Sender,
ActiveVotingRecordIds = { voteId },
ActiveVotedVotesAmount = amount,
AllVotedVotesAmount = amount
@@ -519,7 +516,25 @@ private void UpdateElectorInformation(byte[] recoveredPublicKey, long amount, Ha
voterVotes.AllVotedVotesAmount = voterVotes.AllVotedVotesAmount.Add(amount);
}
- State.ElectorVotes[voterPublicKey] = voterVotes;
+ State.ElectorVotes[Context.Sender.ToBase58()] = voterVotes;
+ }
+
+ private ElectorVote GetElectorVote(byte[] recoveredPublicKey)
+ {
+ var voterVotes = State.ElectorVotes[Context.Sender.ToBase58()];
+ if (voterVotes != null) return voterVotes;
+
+ if (recoveredPublicKey == null) return null;
+
+ var publicKey = recoveredPublicKey.ToHex();
+
+ voterVotes = State.ElectorVotes[publicKey]?.Clone();
+
+ if (voterVotes == null) return null;
+ voterVotes.Address ??= Context.Sender;
+
+ State.ElectorVotes.Remove(publicKey);
+ return voterVotes;
}
///
@@ -620,22 +635,23 @@ public override Empty Withdraw(Hash input)
Assert(actualLockedTime >= claimedLockDays,
$"Still need {claimedLockDays.Sub(actualLockedTime).Div(86400)} days to unlock your token.");
- // Update Elector's Votes information.
- var voterPublicKey = Context.RecoverPublicKey().ToHex();
- var voterVotes = State.ElectorVotes[voterPublicKey];
- if (voterVotes == null) throw new AssertionException($"Voter {voterPublicKey} never votes before.");
+ var voterPublicKey = Context.RecoverPublicKey();
+
+ var voterVotes = GetElectorVote(voterPublicKey);
+
+ Assert(voterVotes != null, $"Voter {Context.Sender.ToBase58()} never votes before");
voterVotes.ActiveVotingRecordIds.Remove(input);
voterVotes.WithdrawnVotingRecordIds.Add(input);
voterVotes.ActiveVotedVotesAmount = voterVotes.ActiveVotedVotesAmount.Sub(votingRecord.Amount);
- State.ElectorVotes[voterPublicKey] = voterVotes;
+
+ State.ElectorVotes[Context.Sender.ToBase58()] = voterVotes;
// Update Candidate's Votes information.
var newestPubkey = GetNewestPubkey(votingRecord.Option);
var candidateVotes = State.CandidateVotes[newestPubkey];
- if (candidateVotes == null)
- throw new AssertionException(
- $"Newest pubkey {newestPubkey} is invalid. Old pubkey is {votingRecord.Option}");
+
+ Assert(candidateVotes != null, $"Newest pubkey {newestPubkey} is invalid. Old pubkey is {votingRecord.Option}");
candidateVotes.ObtainedActiveVotingRecordIds.Remove(input);
candidateVotes.ObtainedWithdrawnVotingRecordIds.Add(input);
@@ -744,12 +760,12 @@ private void NotifyProfitReplaceCandidateInDataCenter(string oldCandidateInDataC
#region subsidy helper
- private Hash GenerateSubsidyId(string pubkey,Address beneficiaryAddress)
+ private Hash GenerateSubsidyId(string pubkey, Address beneficiaryAddress)
{
return HashHelper.ConcatAndCompute(HashHelper.ComputeFrom(pubkey), HashHelper.ComputeFrom(beneficiaryAddress),
HashHelper.ComputeFrom(Context.Self));
}
-
+
private Address GetProfitsReceiverOrDefault(string pubkey)
{
if (State.TreasuryContract.Value == null)
@@ -765,7 +781,7 @@ private Address GetProfitsReceiverOrDefault(string pubkey)
private void AddBeneficiary(string candidatePubkey, Address profitsReceiver = null)
{
var beneficiaryAddress = GetBeneficiaryAddress(candidatePubkey, profitsReceiver);
- var subsidyId = GenerateSubsidyId(candidatePubkey,beneficiaryAddress);
+ var subsidyId = GenerateSubsidyId(candidatePubkey, beneficiaryAddress);
State.ProfitContract.AddBeneficiary.Send(new AddBeneficiaryInput
{
SchemeId = State.SubsidyHash.Value,
@@ -778,10 +794,10 @@ private void AddBeneficiary(string candidatePubkey, Address profitsReceiver = nu
});
}
- private void RemoveBeneficiary(string candidatePubkey,Address profitsReceiver = null)
+ private void RemoveBeneficiary(string candidatePubkey, Address profitsReceiver = null)
{
var beneficiaryAddress = GetBeneficiaryAddress(candidatePubkey, profitsReceiver);
- var previousSubsidyId = GenerateSubsidyId(candidatePubkey,beneficiaryAddress);
+ var previousSubsidyId = GenerateSubsidyId(candidatePubkey, beneficiaryAddress);
State.ProfitContract.RemoveBeneficiary.Send(new RemoveBeneficiaryInput
{
SchemeId = State.SubsidyHash.Value,
@@ -798,6 +814,6 @@ private Address GetBeneficiaryAddress(string candidatePubkey, Address profitsRec
: Address.FromPublicKey(ByteArrayHelper.HexStringToByteArray(candidatePubkey));
return beneficiaryAddress;
}
-
+
#endregion
}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.Election/ViewMethods.cs b/contract/AElf.Contracts.Election/ViewMethods.cs
index e3f318e211..ef8735b3d5 100644
--- a/contract/AElf.Contracts.Election/ViewMethods.cs
+++ b/contract/AElf.Contracts.Election/ViewMethods.cs
@@ -161,20 +161,16 @@ private TermSnapshot GetPreviousTermSnapshotWithNewestPubkey()
public override ElectorVote GetElectorVote(StringValue input)
{
- return State.ElectorVotes[input.Value] ?? new ElectorVote
- {
- Pubkey = ByteStringHelper.FromHexString(input.Value)
- };
+ return GetElectorVote(input.Value);
}
public override ElectorVote GetElectorVoteWithRecords(StringValue input)
{
- var votes = State.ElectorVotes[input.Value];
- if (votes == null)
- return new ElectorVote
- {
- Pubkey = ByteStringHelper.FromHexString(input.Value)
- };
+ var votes = GetElectorVote(input.Value);
+
+ if (votes.Address == null && votes.Pubkey == null)
+ return votes;
+
var votedRecords = State.VoteContract.GetVotingRecords.Call(new GetVotingRecordsInput
{
Ids = { votes.ActiveVotingRecordIds }
@@ -189,6 +185,21 @@ public override ElectorVote GetElectorVoteWithRecords(StringValue input)
return votes;
}
+ private ElectorVote GetElectorVote(string value)
+ {
+ Assert(value != null && value.Length > 1, "Invalid input.");
+
+ var voterVotes = State.ElectorVotes[value];
+
+ if (voterVotes == null && !AddressHelper.VerifyFormattedAddress(value))
+ {
+ voterVotes = State.ElectorVotes[
+ Address.FromPublicKey(ByteArrayHelper.HexStringToByteArray(value)).ToBase58()];
+ }
+
+ return voterVotes ?? new ElectorVote();
+ }
+
public override ElectorVote GetElectorVoteWithAllRecords(StringValue input)
{
var votes = GetElectorVoteWithRecords(input);
diff --git a/contract/AElf.Contracts.Genesis/BasicContractZero.cs b/contract/AElf.Contracts.Genesis/BasicContractZero.cs
index ff29b81689..9f47577bed 100644
--- a/contract/AElf.Contracts.Genesis/BasicContractZero.cs
+++ b/contract/AElf.Contracts.Genesis/BasicContractZero.cs
@@ -365,6 +365,7 @@ public override Empty SetContractProposalExpirationTimePeriod(SetContractProposa
public override DeployUserSmartContractOutput DeployUserSmartContract(ContractDeploymentInput input)
{
+ AssertInlineDeployOrUpdateUserContract();
AssertUserDeployContract();
var codeHash = HashHelper.ComputeFrom(input.Code.ToByteArray());
@@ -395,6 +396,8 @@ public override DeployUserSmartContractOutput DeployUserSmartContract(ContractDe
public override Empty UpdateUserSmartContract(ContractUpdateInput input)
{
+ AssertInlineDeployOrUpdateUserContract();
+
var info = State.ContractInfos[input.Address];
Assert(info != null, "Contract not found.");
Assert(Context.Sender == info.Author, "No permission.");
diff --git a/contract/AElf.Contracts.Genesis/BasicContractZero_Helper.cs b/contract/AElf.Contracts.Genesis/BasicContractZero_Helper.cs
index 04aa2da726..40678c4203 100644
--- a/contract/AElf.Contracts.Genesis/BasicContractZero_Helper.cs
+++ b/contract/AElf.Contracts.Genesis/BasicContractZero_Helper.cs
@@ -359,6 +359,16 @@ private void AssertContractExists(Hash codeHash)
{
Assert(State.SmartContractRegistrations[codeHash] == null, "contract code has already been deployed before.");
}
+
+ private void AssertInlineDeployOrUpdateUserContract()
+ {
+ Assert(Context.Origin == Context.Sender || !IsMainChain(), "Deploy or update contracts using inline transactions is not allowed.");
+ }
+
+ private bool IsMainChain()
+ {
+ return Context.GetContractAddressByName(SmartContractConstants.TreasuryContractSystemName) != null;
+ }
}
public static class AddressHelper
diff --git a/contract/AElf.Contracts.MultiToken/TokenContractConstants.cs b/contract/AElf.Contracts.MultiToken/TokenContractConstants.cs
index 2f407988d3..a14a4e9496 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContractConstants.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContractConstants.cs
@@ -14,8 +14,12 @@ public static class TokenContractConstants
public const string LockCallbackExternalInfoKey = "aelf_lock_callback";
public const string UnlockCallbackExternalInfoKey = "aelf_unlock_callback";
public const string LogEventExternalInfoKey = "aelf_log_event";
- public const int DELEGATEE_MAX_COUNT = 128;
+ public const int DELEGATEE_MAX_COUNT = 24;
public const char NFTSymbolSeparator = '-';
public const int NFTSymbolMaxLength = 30;
- public const string UserContractMethodFeeKey = "UserContractMethodFee";
+ public const string UserContractMethodFeeKey = "UserContractMethodFee";
+ public const string CollectionSymbolSuffix = "0";
+ public const string SeedCollectionSymbol = "SEED-0";
+ public const string SeedOwnedSymbolExternalInfoKey = "__seed_owned_symbol";
+ public const string SeedExpireTimeExternalInfoKey = "__seed_exp_time";
}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.MultiToken/TokenContractState.cs b/contract/AElf.Contracts.MultiToken/TokenContractState.cs
index cac95c40af..92da423908 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContractState.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContractState.cs
@@ -9,6 +9,7 @@ public partial class TokenContractState : ContractState
public StringState ChainPrimaryTokenSymbol { get; set; }
public MappedState TokenInfos { get; set; }
+ public MappedState SymbolSeedMap { get; set; }
public MappedState Balances { get; set; }
public MappedState Allowances { get; set; }
@@ -54,4 +55,12 @@ public partial class TokenContractState : ContractState
public MappedState CreateTokenWhiteListMap { get; set; }
public MappedState TransactionFeeDelegateesMap { get; set; }
+
+ ///
+ /// delegator address -> contract address -> method name -> delegatee info
+ ///
+ public MappedState TransactionFeeDelegateInfoMap { get; set; }
+
+ public SingletonState ElectionContractAddress { get; set; }
+ public SingletonState VoteContractAddress { get; set; }
}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.MultiToken/TokenContractState_ChargeFee.cs b/contract/AElf.Contracts.MultiToken/TokenContractState_ChargeFee.cs
index 9fdf6cbe0c..d841f24d7e 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContractState_ChargeFee.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContractState_ChargeFee.cs
@@ -34,8 +34,28 @@ public partial class TokenContractState
/// Symbol -> Amount
///
public MappedState OwningRental { get; set; }
-
+
public SingletonState MethodFeeFreeAllowancesConfig { get; set; }
public MappedState MethodFeeFreeAllowancesMap { get; set; }
public MappedState MethodFeeFreeAllowancesLastRefreshTimeMap { get; set; }
+
+ ///
+ /// Symbol List
+ ///
+ public SingletonState TransactionFeeFreeAllowancesSymbolList { get; set; }
+
+ ///
+ /// Symbol -> TransactionFeeFreeAllowanceConfig
+ ///
+ public MappedState TransactionFeeFreeAllowancesConfigMap { get; set; }
+
+ ///
+ /// Address -> Symbol -> TransactionFeeFreeAllowanceMap
+ ///
+ public MappedState TransactionFeeFreeAllowances { get; set; }
+
+ ///
+ /// Address -> Symbol -> LastRefreshTime
+ ///
+ public MappedState TransactionFeeFreeAllowancesLastRefreshTimes { get; set; }
}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.MultiToken/TokenContract_ACS1_MethodFeeProvider.cs b/contract/AElf.Contracts.MultiToken/TokenContract_ACS1_MethodFeeProvider.cs
index ff15f9a9c6..9ef198b39c 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContract_ACS1_MethodFeeProvider.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContract_ACS1_MethodFeeProvider.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using AElf.Sdk.CSharp;
using AElf.Standards.ACS1;
using AElf.Standards.ACS3;
@@ -47,20 +48,6 @@ public override MethodFees GetMethodFee(StringValue input)
IsSizeFeeFree = true
};
var fees = State.TransactionFees[input.Value];
- if (input.Value == nameof(Create) && fees == null)
- return new MethodFees
- {
- MethodName = input.Value,
- Fees =
- {
- new MethodFee
- {
- Symbol = Context.Variables.NativeSymbol,
- BasicFee = 10000_00000000
- }
- }
- };
-
return fees;
}
@@ -74,14 +61,33 @@ public override AuthorityInfo GetMethodFeeController(Empty input)
#region private methods
- private List GetMethodFeeSymbols()
+ private List GetTransactionFeeSymbols(string methodName)
{
var symbols = new List();
- var primaryTokenSymbol = GetPrimaryTokenSymbol(new Empty()).Value;
- if (primaryTokenSymbol != string.Empty) symbols.Add(primaryTokenSymbol);
+ if (State.TransactionFees[methodName] != null)
+ {
+ foreach (var methodFee in State.TransactionFees[methodName].Fees)
+ {
+ if (!symbols.Contains(methodFee.Symbol) && methodFee.BasicFee > 0)
+ symbols.Add(methodFee.Symbol);
+ }
+ if (State.TransactionFees[methodName].IsSizeFeeFree)
+ {
+ return symbols;
+ }
+ }
+
+ if (State.SymbolListToPayTxSizeFee.Value == null) return symbols;
+
+ foreach (var sizeFee in State.SymbolListToPayTxSizeFee.Value.SymbolsToPayTxSizeFee)
+ {
+ if (!symbols.Contains(sizeFee.TokenSymbol))
+ symbols.Add(sizeFee.TokenSymbol);
+ }
return symbols;
}
+
private void RequiredMethodFeeControllerSet()
{
if (State.MethodFeeController.Value != null) return;
diff --git a/contract/AElf.Contracts.MultiToken/TokenContract_ACS2_StatePathsProvider.cs b/contract/AElf.Contracts.MultiToken/TokenContract_ACS2_StatePathsProvider.cs
index bf075eec0c..8d12f604e1 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContract_ACS2_StatePathsProvider.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContract_ACS2_StatePathsProvider.cs
@@ -1,4 +1,4 @@
-using System;
+using System.Collections.Generic;
using System.Linq;
using AElf.Standards.ACS2;
using AElf.Types;
@@ -20,19 +20,20 @@ public override ResourceInfo GetResourceInfo(Transaction txn)
WritePaths =
{
GetPath(nameof(TokenContractState.Balances), txn.From.ToString(), args.Symbol),
- GetPath(nameof(TokenContractState.Balances), args.To.ToString(), args.Symbol),
- GetPath(nameof(TokenContractState.MethodFeeFreeAllowancesMap), txn.From.ToString()),
- GetPath(nameof(TokenContractState.MethodFeeFreeAllowancesLastRefreshTimeMap), txn.From.ToString())
+ GetPath(nameof(TokenContractState.Balances), args.To.ToString(), args.Symbol)
},
ReadPaths =
{
GetPath(nameof(TokenContractState.TokenInfos), args.Symbol),
GetPath(nameof(TokenContractState.ChainPrimaryTokenSymbol)),
- GetPath(nameof(TokenContractState.MethodFeeFreeAllowancesConfig))
+ GetPath(nameof(TokenContractState.TransactionFeeFreeAllowancesSymbolList))
}
};
- AddPathForTransactionFee(resourceInfo, txn.From.ToString());
- AddPathForDelegatees(resourceInfo, txn.From);
+
+ AddPathForTransactionFee(resourceInfo, txn.From.ToString(), txn.MethodName);
+ AddPathForDelegatees(resourceInfo, txn.From, txn.To, txn.MethodName);
+ AddPathForTransactionFeeFreeAllowance(resourceInfo, txn.From);
+
return resourceInfo;
}
@@ -47,19 +48,20 @@ public override ResourceInfo GetResourceInfo(Transaction txn)
args.Symbol),
GetPath(nameof(TokenContractState.Balances), args.From.ToString(), args.Symbol),
GetPath(nameof(TokenContractState.Balances), args.To.ToString(), args.Symbol),
- GetPath(nameof(TokenContractState.LockWhiteLists), args.Symbol, txn.From.ToString()),
- GetPath(nameof(TokenContractState.MethodFeeFreeAllowancesMap), txn.From.ToString()),
- GetPath(nameof(TokenContractState.MethodFeeFreeAllowancesLastRefreshTimeMap), txn.From.ToString())
+ GetPath(nameof(TokenContractState.LockWhiteLists), args.Symbol, txn.From.ToString())
},
ReadPaths =
{
GetPath(nameof(TokenContractState.TokenInfos), args.Symbol),
GetPath(nameof(TokenContractState.ChainPrimaryTokenSymbol)),
- GetPath(nameof(TokenContractState.MethodFeeFreeAllowancesConfig))
+ GetPath(nameof(TokenContractState.TransactionFeeFreeAllowancesSymbolList))
}
};
- AddPathForTransactionFee(resourceInfo, txn.From.ToString());
- AddPathForDelegatees(resourceInfo, txn.From);
+
+ AddPathForTransactionFee(resourceInfo, txn.From.ToString(), txn.MethodName);
+ AddPathForDelegatees(resourceInfo, txn.From, txn.To, txn.MethodName);
+ AddPathForTransactionFeeFreeAllowance(resourceInfo, txn.From);
+
return resourceInfo;
}
@@ -68,9 +70,10 @@ public override ResourceInfo GetResourceInfo(Transaction txn)
}
}
- private void AddPathForTransactionFee(ResourceInfo resourceInfo, String from)
+
+ private void AddPathForTransactionFee(ResourceInfo resourceInfo, string from, string methodName)
{
- var symbols = GetMethodFeeSymbols();
+ var symbols = GetTransactionFeeSymbols(methodName);
var primaryTokenSymbol = GetPrimaryTokenSymbol(new Empty()).Value;
if (_primaryTokenSymbol != string.Empty && !symbols.Contains(primaryTokenSymbol))
symbols.Add(primaryTokenSymbol);
@@ -95,20 +98,60 @@ private ScopedStatePath GetPath(params string[] parts)
}
}
};
- }
-
- private void AddPathForDelegatees(ResourceInfo resourceInfo, Address from)
+ }
+
+ private void AddPathForDelegatees(ResourceInfo resourceInfo, Address from, Address to, string methodName)
{
- var allDelegatees = State.TransactionFeeDelegateesMap[from];
+ var delegateeList = new List();
+ //get and add first-level delegatee list
+ delegateeList.AddRange(GetDelegateeList(from, to, methodName));
+ if (delegateeList.Count <= 0) return;
+ var secondDelegateeList = new List();
+ //get and add second-level delegatee list
+ foreach (var delegateeAddress in delegateeList.Select(Address.FromBase58))
+ {
+ //delegatee of the first-level delegate is delegator of the second-level delegate
+ secondDelegateeList.AddRange(GetDelegateeList(delegateeAddress, to, methodName));
+ }
+ delegateeList.AddRange(secondDelegateeList);
+ foreach (var delegatee in delegateeList.Distinct())
+ {
+ AddPathForTransactionFee(resourceInfo, delegatee, methodName);
+ AddPathForTransactionFeeFreeAllowance(resourceInfo, Address.FromBase58(delegatee));
+ }
+ }
+
+ private List GetDelegateeList(Address delegator, Address to, string methodName)
+ {
+ var delegateeList = new List();
+ var allDelegatees = State.TransactionFeeDelegateInfoMap[delegator][to][methodName]
+ ?? State.TransactionFeeDelegateesMap[delegator];
+
if (allDelegatees != null)
{
- foreach (var delegations in allDelegatees.Delegatees.Keys)
+ delegateeList.AddRange(allDelegatees.Delegatees.Keys.ToList());
+ }
+
+ return delegateeList;
+ }
+
+ private void AddPathForTransactionFeeFreeAllowance(ResourceInfo resourceInfo, Address from)
+ {
+ var symbols = State.TransactionFeeFreeAllowancesSymbolList.Value?.Symbols;
+ if (symbols != null)
+ {
+ foreach (var symbol in symbols)
{
- if (delegations == null) return;
- var add = Address.FromBase58(delegations).ToString();
- AddPathForTransactionFee(resourceInfo, add);
- resourceInfo.WritePaths.Add(GetPath(nameof(TokenContractState.MethodFeeFreeAllowancesMap), add));
- resourceInfo.WritePaths.Add(GetPath(nameof(TokenContractState.MethodFeeFreeAllowancesLastRefreshTimeMap), add));
+ resourceInfo.WritePaths.Add(GetPath(nameof(TokenContractState.TransactionFeeFreeAllowances),
+ from.ToBase58(), symbol));
+ resourceInfo.WritePaths.Add(GetPath(
+ nameof(TokenContractState.TransactionFeeFreeAllowancesLastRefreshTimes), from.ToBase58(), symbol));
+
+ var path = GetPath(nameof(TokenContractState.TransactionFeeFreeAllowancesConfigMap), symbol);
+ if (!resourceInfo.ReadPaths.Contains(path))
+ {
+ resourceInfo.ReadPaths.Add(path);
+ }
}
}
}
diff --git a/contract/AElf.Contracts.MultiToken/TokenContract_Actions.cs b/contract/AElf.Contracts.MultiToken/TokenContract_Actions.cs
index f627b867a7..483f073b54 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContract_Actions.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContract_Actions.cs
@@ -35,7 +35,10 @@ public override Empty Create(CreateInput input)
// can not call create on side chain
Assert(State.SideChainCreator.Value == null, "Failed to create token if side chain creator already set.");
var inputSymbolType = GetCreateInputSymbolType(input.Symbol);
- ChargeCreateFees();
+ if (input.Owner == null)
+ {
+ input.Owner = input.Issuer;
+ }
return inputSymbolType switch
{
SymbolType.NftCollection => CreateNFTCollection(input),
@@ -47,6 +50,20 @@ public override Empty Create(CreateInput input)
private Empty CreateToken(CreateInput input, SymbolType symbolType = SymbolType.Token)
{
AssertValidCreateInput(input, symbolType);
+ if (symbolType == SymbolType.Token || symbolType == SymbolType.NftCollection)
+ {
+ if (!IsAddressInCreateWhiteList(Context.Sender) &&
+ input.Symbol != TokenContractConstants.SeedCollectionSymbol)
+ {
+ var symbolSeed = State.SymbolSeedMap[input.Symbol];
+ CheckSeedNFT(symbolSeed, input.Symbol);
+ // seed nft for one-time use only
+ long balance = State.Balances[Context.Sender][symbolSeed];
+ DoTransferFrom(Context.Sender, Context.Self, Context.Self, symbolSeed, balance, "");
+ Burn(Context.Self, symbolSeed, balance);
+ }
+ }
+
var tokenInfo = new TokenInfo
{
Symbol = input.Symbol,
@@ -56,7 +73,8 @@ private Empty CreateToken(CreateInput input, SymbolType symbolType = SymbolType.
Issuer = input.Issuer,
IsBurnable = input.IsBurnable,
IssueChainId = input.IssueChainId == 0 ? Context.ChainId : input.IssueChainId,
- ExternalInfo = input.ExternalInfo ?? new ExternalInfo()
+ ExternalInfo = input.ExternalInfo ?? new ExternalInfo(),
+ Owner = input.Owner
};
RegisterTokenInfo(tokenInfo);
if (string.IsNullOrEmpty(State.NativeTokenSymbol.Value))
@@ -81,12 +99,29 @@ private Empty CreateToken(CreateInput input, SymbolType symbolType = SymbolType.
Issuer = tokenInfo.Issuer,
IsBurnable = tokenInfo.IsBurnable,
IssueChainId = tokenInfo.IssueChainId,
- ExternalInfo = tokenInfo.ExternalInfo
+ ExternalInfo = tokenInfo.ExternalInfo,
+ Owner = tokenInfo.Owner
});
return new Empty();
}
+ private void CheckSeedNFT(string symbolSeed, String symbol)
+ {
+ Assert(!string.IsNullOrEmpty(symbolSeed), "Seed NFT does not exist.");
+ var tokenInfo = State.TokenInfos[symbolSeed];
+ Assert(tokenInfo != null, "Seed NFT does not exist.");
+ Assert(State.Balances[Context.Sender][symbolSeed] > 0, "Seed NFT balance is not enough.");
+ Assert(tokenInfo.ExternalInfo != null && tokenInfo.ExternalInfo.Value.TryGetValue(
+ TokenContractConstants.SeedOwnedSymbolExternalInfoKey, out var ownedSymbol) && ownedSymbol == symbol,
+ "Invalid OwnedSymbol.");
+ Assert(tokenInfo.ExternalInfo.Value.TryGetValue(TokenContractConstants.SeedExpireTimeExternalInfoKey,
+ out var expirationTime)
+ && long.TryParse(expirationTime, out var expirationTimeLong) &&
+ Context.CurrentBlockTime.Seconds <= expirationTimeLong, "OwnedSymbol is expired.");
+ }
+
+
///
/// Set primary token symbol.
///
@@ -95,7 +130,7 @@ private Empty CreateToken(CreateInput input, SymbolType symbolType = SymbolType.
public override Empty SetPrimaryTokenSymbol(SetPrimaryTokenSymbolInput input)
{
Assert(State.ChainPrimaryTokenSymbol.Value == null, "Failed to set primary token symbol.");
- Assert(State.TokenInfos[input.Symbol] != null, "Invalid input.");
+ Assert(!string.IsNullOrWhiteSpace(input.Symbol) && State.TokenInfos[input.Symbol] != null, "Invalid input symbol.");
State.ChainPrimaryTokenSymbol.Value = input.Symbol;
Context.Fire(new ChainPrimaryTokenSymbolSet { TokenSymbol = input.Symbol });
@@ -150,8 +185,13 @@ public override Empty Transfer(TransferInput input)
public override Empty Lock(LockInput input)
{
+ Assert(!string.IsNullOrWhiteSpace(input.Symbol), "Invalid input symbol.");
+ AssertValidInputAddress(input.Address);
AssertSystemContractOrLockWhiteListAddress(input.Symbol);
- Assert(Context.Origin == input.Address, "Lock behaviour should be initialed by origin address.");
+
+ Assert(IsInLockWhiteList(Context.Sender) || Context.Origin == input.Address,
+ "Lock behaviour should be initialed by origin address.");
+
var allowance = State.Allowances[input.Address][Context.Sender][input.Symbol];
if (allowance >= input.Amount)
State.Allowances[input.Address][Context.Sender][input.Symbol] = allowance.Sub(input.Amount);
@@ -174,8 +214,13 @@ public override Empty Lock(LockInput input)
public override Empty Unlock(UnlockInput input)
{
+ Assert(!string.IsNullOrWhiteSpace(input.Symbol), "Invalid input symbol.");
+ AssertValidInputAddress(input.Address);
AssertSystemContractOrLockWhiteListAddress(input.Symbol);
- Assert(Context.Origin == input.Address, "Unlock behaviour should be initialed by origin address.");
+
+ Assert(IsInLockWhiteList(Context.Sender) || Context.Origin == input.Address,
+ "Unlock behaviour should be initialed by origin address.");
+
AssertValidToken(input.Symbol, input.Amount);
var fromVirtualAddress = HashHelper.ComputeFrom(Context.Sender.Value.Concat(input.Address.Value)
.Concat(input.LockId.Value).ToArray());
@@ -206,6 +251,7 @@ public override Empty TransferFrom(TransferFromInput input)
public override Empty Approve(ApproveInput input)
{
+ AssertValidInputAddress(input.Spender);
AssertValidToken(input.Symbol, input.Amount);
State.Allowances[Context.Sender][input.Spender][input.Symbol] = input.Amount;
Context.Fire(new Approved
@@ -220,6 +266,7 @@ public override Empty Approve(ApproveInput input)
public override Empty UnApprove(UnApproveInput input)
{
+ AssertValidInputAddress(input.Spender);
AssertValidToken(input.Symbol, input.Amount);
var oldAllowance = State.Allowances[Context.Sender][input.Spender][input.Symbol];
var amountOrAll = Math.Min(input.Amount, oldAllowance);
@@ -236,22 +283,28 @@ public override Empty UnApprove(UnApproveInput input)
public override Empty Burn(BurnInput input)
{
- var tokenInfo = AssertValidToken(input.Symbol, input.Amount);
+ return Burn(Context.Sender, input.Symbol, input.Amount);
+ }
+
+ private Empty Burn(Address address, string symbol, long amount)
+ {
+ var tokenInfo = AssertValidToken(symbol, amount);
Assert(tokenInfo.IsBurnable, "The token is not burnable.");
- ModifyBalance(Context.Sender, input.Symbol, -input.Amount);
- tokenInfo.Supply = tokenInfo.Supply.Sub(input.Amount);
+ ModifyBalance(address, symbol, -amount);
+ tokenInfo.Supply = tokenInfo.Supply.Sub(amount);
Context.Fire(new Burned
{
- Burner = Context.Sender,
- Symbol = input.Symbol,
- Amount = input.Amount
+ Burner = address,
+ Symbol = symbol,
+ Amount = amount
});
return new Empty();
}
public override Empty CheckThreshold(CheckThresholdInput input)
{
+ AssertValidInputAddress(input.Sender);
var meetThreshold = false;
var meetBalanceSymbolList = new List();
foreach (var symbolToThreshold in input.SymbolToThreshold)
@@ -323,6 +376,7 @@ public override Empty TransferToContract(TransferToContractInput input)
public override Empty AdvanceResourceToken(AdvanceResourceTokenInput input)
{
+ AssertValidInputAddress(input.ContractAddress);
Assert(
Context.Variables.GetStringArray(TokenContractConstants.PayTxFeeSymbolListName)
.Contains(input.ResourceTokenSymbol),
@@ -336,6 +390,8 @@ public override Empty AdvanceResourceToken(AdvanceResourceTokenInput input)
public override Empty TakeResourceTokenBack(TakeResourceTokenBackInput input)
{
+ Assert(!string.IsNullOrWhiteSpace(input.ResourceTokenSymbol), "Invalid input resource token symbol.");
+ AssertValidInputAddress(input.ContractAddress);
var advancedAmount =
State.AdvancedResourceToken[input.ContractAddress][Context.Sender][input.ResourceTokenSymbol];
Assert(advancedAmount >= input.Amount, "Can't take back that more.");
@@ -347,13 +403,14 @@ public override Empty TakeResourceTokenBack(TakeResourceTokenBackInput input)
public override Empty ValidateTokenInfoExists(ValidateTokenInfoExistsInput input)
{
+ Assert(!string.IsNullOrWhiteSpace(input.Symbol), "Invalid input symbol.");
var tokenInfo = State.TokenInfos[input.Symbol];
if (tokenInfo == null) throw new AssertionException("Token validation failed.");
var validationResult = tokenInfo.TokenName == input.TokenName &&
tokenInfo.IsBurnable == input.IsBurnable && tokenInfo.Decimals == input.Decimals &&
tokenInfo.Issuer == input.Issuer && tokenInfo.TotalSupply == input.TotalSupply &&
- tokenInfo.IssueChainId == input.IssueChainId;
+ tokenInfo.IssueChainId == input.IssueChainId && tokenInfo.Owner == input.Owner;
if (tokenInfo.ExternalInfo != null && tokenInfo.ExternalInfo.Value.Count > 0 ||
input.ExternalInfo != null && input.ExternalInfo.Count > 0)
@@ -368,32 +425,6 @@ public override Empty ValidateTokenInfoExists(ValidateTokenInfoExistsInput input
return new Empty();
}
- public override Empty ChangeTokenIssuer(ChangeTokenIssuerInput input)
- {
- var tokenInfo = State.TokenInfos[input.Symbol];
- Assert(tokenInfo != null, $"invalid token symbol: {input.Symbol}");
- // ReSharper disable once PossibleNullReferenceException
- Assert(tokenInfo.Issuer == Context.Sender && tokenInfo.IssueChainId == Context.ChainId,
- "Permission denied");
- tokenInfo.Issuer = input.NewTokenIssuer;
- State.TokenInfos[input.Symbol] = tokenInfo;
- return new Empty();
- }
-
- public override Empty ResetExternalInfo(ResetExternalInfoInput input)
- {
- var tokenInfo = State.TokenInfos[input.Symbol];
- Assert(tokenInfo.Issuer == Context.Sender, "No permission to reset external info.");
- tokenInfo.ExternalInfo = input.ExternalInfo;
- State.TokenInfos[input.Symbol] = tokenInfo;
- Context.Fire(new ExternalInfoChanged
- {
- Symbol = input.Symbol,
- ExternalInfo = input.ExternalInfo
- });
- return new Empty();
- }
-
public override Empty AddAddressToCreateTokenWhiteList(Address input)
{
AssertSenderAddressWith(GetDefaultParliamentController().OwnerAddress);
@@ -433,7 +464,8 @@ public override Empty CrossChainCreateToken(CrossChainCreateTokenInput input)
Issuer = validateTokenInfoExistsInput.Issuer,
IsBurnable = validateTokenInfoExistsInput.IsBurnable,
IssueChainId = validateTokenInfoExistsInput.IssueChainId,
- ExternalInfo = new ExternalInfo { Value = { validateTokenInfoExistsInput.ExternalInfo } }
+ ExternalInfo = new ExternalInfo { Value = { validateTokenInfoExistsInput.ExternalInfo } },
+ Owner = validateTokenInfoExistsInput.Owner ?? validateTokenInfoExistsInput.Issuer
};
RegisterTokenInfo(tokenInfo);
@@ -446,7 +478,8 @@ public override Empty CrossChainCreateToken(CrossChainCreateTokenInput input)
Issuer = validateTokenInfoExistsInput.Issuer,
IsBurnable = validateTokenInfoExistsInput.IsBurnable,
IssueChainId = validateTokenInfoExistsInput.IssueChainId,
- ExternalInfo = new ExternalInfo { Value = { validateTokenInfoExistsInput.ExternalInfo } }
+ ExternalInfo = new ExternalInfo { Value = { validateTokenInfoExistsInput.ExternalInfo } },
+ Owner = tokenInfo.Owner
});
return new Empty();
diff --git a/contract/AElf.Contracts.MultiToken/TokenContract_Delegation.cs b/contract/AElf.Contracts.MultiToken/TokenContract_Delegation.cs
index b38acad74a..1ac302ccef 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContract_Delegation.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContract_Delegation.cs
@@ -1,3 +1,4 @@
+using System.Collections.Generic;
using System.Linq;
using AElf.Sdk.CSharp;
using AElf.Types;
@@ -11,6 +12,7 @@ public partial class TokenContract
public override SetTransactionFeeDelegationsOutput SetTransactionFeeDelegations(
SetTransactionFeeDelegationsInput input)
{
+ AssertValidInputAddress(input.DelegatorAddress);
Assert(input.Delegations != null, "Delegations cannot be null!");
// get all delegatees, init it if null.
@@ -192,4 +194,240 @@ public override GetTransactionFeeDelegateesOutput GetTransactionFeeDelegatees(
DelegateeAddresses = { allDelegatees.Delegatees.Keys.Select(Address.FromBase58) }
};
}
+
+ public override Empty SetTransactionFeeDelegateInfos(SetTransactionFeeDelegateInfosInput input)
+ {
+ Assert(input.DelegatorAddress != null && input.DelegateInfoList.Count > 0,
+ "Delegator address and delegate info cannot be null.");
+ var toAddTransactionList = new DelegateTransactionList();
+ var toUpdateTransactionList = new DelegateTransactionList();
+ var toCancelTransactionList = new DelegateTransactionList();
+ var delegatorAddress = input.DelegatorAddress;
+ foreach (var delegateInfo in input.DelegateInfoList)
+ {
+ //If isUnlimitedDelegate is false,delegate info list should > 0.
+ Assert(delegateInfo.IsUnlimitedDelegate || delegateInfo.Delegations.Count > 0,
+ "Delegation cannot be null.");
+ Assert(delegateInfo.ContractAddress != null && !string.IsNullOrEmpty(delegateInfo.MethodName),
+ "Invalid contract address and method name.");
+
+ var existDelegateeInfoList =
+ State.TransactionFeeDelegateInfoMap[delegatorAddress][delegateInfo.ContractAddress]
+ [delegateInfo.MethodName] ?? new TransactionFeeDelegatees();
+ var delegateeAddress = Context.Sender.ToBase58();
+ var existDelegateeList = existDelegateeInfoList.Delegatees;
+ //If the transaction contains delegatee,update delegate info.
+ if (existDelegateeList.TryGetValue(delegateeAddress, out var value))
+ {
+ toUpdateTransactionList.Value.Add(UpdateDelegateInfo(value, delegateInfo));
+ } //else,add new delegate info.
+ else
+ {
+ Assert(existDelegateeList.Count < TokenContractConstants.DELEGATEE_MAX_COUNT,
+ "The quantity of delegatee has reached its limit");
+ existDelegateeList.Add(delegateeAddress, new TransactionFeeDelegations());
+ var transactionFeeDelegations = existDelegateeList[delegateeAddress];
+ toAddTransactionList.Value.Add(AddDelegateInfo(transactionFeeDelegations, delegateInfo));
+ }
+
+ if (existDelegateeInfoList.Delegatees[delegateeAddress].Delegations.Count == 0 &&
+ !existDelegateeInfoList.Delegatees[delegateeAddress].IsUnlimitedDelegate)
+ {
+ existDelegateeInfoList.Delegatees.Remove(delegateeAddress);
+ toCancelTransactionList.Value.Add(new DelegateTransaction
+ {
+ ContractAddress = delegateInfo.ContractAddress,
+ MethodName = delegateInfo.MethodName
+ });
+ }
+
+ State.TransactionFeeDelegateInfoMap[delegatorAddress][delegateInfo.ContractAddress]
+ [delegateInfo.MethodName] = existDelegateeInfoList;
+ }
+
+ FireLogEvent(toAddTransactionList, toUpdateTransactionList, toCancelTransactionList, delegatorAddress);
+
+ return new Empty();
+ }
+
+ private DelegateTransaction AddDelegateInfo(TransactionFeeDelegations existDelegateeList, DelegateInfo delegateInfo)
+ {
+ if (!delegateInfo.IsUnlimitedDelegate)
+ {
+ foreach (var (symbol, amount) in delegateInfo.Delegations)
+ {
+ AssertValidToken(symbol, amount);
+ existDelegateeList.Delegations[symbol] = amount;
+ }
+ }
+ existDelegateeList.BlockHeight = Context.CurrentHeight;
+ existDelegateeList.IsUnlimitedDelegate = delegateInfo.IsUnlimitedDelegate;
+ return new DelegateTransaction
+ {
+ ContractAddress = delegateInfo.ContractAddress,
+ MethodName = delegateInfo.MethodName
+ };
+ }
+
+ private DelegateTransaction UpdateDelegateInfo(TransactionFeeDelegations existDelegateInfo, DelegateInfo delegateInfo)
+ {
+ var existDelegation = existDelegateInfo.Delegations;
+ if (delegateInfo.IsUnlimitedDelegate)
+ {
+ existDelegation.Clear();
+ }
+ else
+ {
+ var delegation = delegateInfo.Delegations;
+ foreach (var (symbol, amount) in delegation)
+ {
+ if (existDelegation.ContainsKey(symbol))
+ {
+ if (amount <= 0)
+ {
+ existDelegation.Remove(symbol);
+ }
+ else
+ {
+ AssertValidToken(symbol, amount);
+ existDelegation[symbol] = amount;
+ }
+ }
+ else
+ {
+ AssertValidToken(symbol, amount);
+ existDelegation[symbol] = amount;
+ }
+ }
+ }
+
+ existDelegateInfo.BlockHeight = Context.CurrentHeight;
+ existDelegateInfo.IsUnlimitedDelegate = delegateInfo.IsUnlimitedDelegate;
+ return new DelegateTransaction
+ {
+ ContractAddress = delegateInfo.ContractAddress,
+ MethodName = delegateInfo.MethodName
+ };
+ }
+
+ private void FireLogEvent(DelegateTransactionList toAddTransactionList,
+ DelegateTransactionList toUpdateTransactionList, DelegateTransactionList toCancelTransactionList,
+ Address delegatorAddress)
+ {
+ if (toAddTransactionList.Value.Count > 0)
+ {
+ Context.Fire(new TransactionFeeDelegateInfoAdded
+ {
+ Caller = Context.Sender,
+ Delegatee = Context.Sender,
+ Delegator = delegatorAddress,
+ DelegateTransactionList = toAddTransactionList
+ });
+ }
+
+ if (toUpdateTransactionList.Value.Count > 0)
+ {
+ Context.Fire(new TransactionFeeDelegateInfoUpdated
+ {
+ Caller = Context.Sender,
+ Delegatee = Context.Sender,
+ Delegator = delegatorAddress,
+ DelegateTransactionList = toUpdateTransactionList
+ });
+ }
+
+ if (toCancelTransactionList.Value.Count > 0)
+ {
+ Context.Fire(new TransactionFeeDelegateInfoCancelled
+ {
+ Caller = Context.Sender,
+ Delegatee = Context.Sender,
+ Delegator = delegatorAddress,
+ DelegateTransactionList = toCancelTransactionList
+ });
+ }
+ }
+
+ public override Empty RemoveTransactionFeeDelegateeInfos(RemoveTransactionFeeDelegateeInfosInput input)
+ {
+ Assert(input.DelegateeAddress != null, "Delegatee address cannot be null.");
+ Assert(input.DelegateTransactionList.Count > 0, "Delegate transaction list should not be null.");
+ var delegatorAddress = Context.Sender;
+ var delegateeAddress = input.DelegateeAddress?.ToBase58();
+ RemoveTransactionFeeDelegateInfo(input.DelegateTransactionList.ToList(), delegatorAddress, delegateeAddress);
+ return new Empty();
+ }
+
+ public override Empty RemoveTransactionFeeDelegatorInfos(RemoveTransactionFeeDelegatorInfosInput input)
+ {
+ Assert(input.DelegatorAddress != null, "Delegator address cannot be null.");
+ Assert(input.DelegateTransactionList.Count > 0, "Delegate transaction list should not be null.");
+ var delegateeAddress = Context.Sender.ToBase58();
+ var delegatorAddress = input.DelegatorAddress;
+ RemoveTransactionFeeDelegateInfo(input.DelegateTransactionList.ToList(), delegatorAddress, delegateeAddress);
+ return new Empty();
+ }
+
+ private void RemoveTransactionFeeDelegateInfo(List delegateTransactionList,Address delegatorAddress,string delegateeAddress)
+ {
+ var toCancelTransactionList = new DelegateTransactionList();
+ foreach (var delegateTransaction in delegateTransactionList.Distinct())
+ {
+ Assert(delegateTransaction.ContractAddress != null && !string.IsNullOrEmpty(delegateTransaction.MethodName),
+ "Invalid contract address and method name.");
+
+ var delegateeInfo =
+ State.TransactionFeeDelegateInfoMap[delegatorAddress][delegateTransaction.ContractAddress][
+ delegateTransaction.MethodName];
+ if (delegateeInfo == null || !delegateeInfo.Delegatees.ContainsKey(delegateeAddress)) continue;
+ delegateeInfo.Delegatees.Remove(delegateeAddress);
+ toCancelTransactionList.Value.Add(delegateTransaction);
+ State.TransactionFeeDelegateInfoMap[delegatorAddress][delegateTransaction.ContractAddress][
+ delegateTransaction.MethodName] = delegateeInfo;
+ }
+
+ if (toCancelTransactionList.Value.Count > 0)
+ {
+ Context.Fire(new TransactionFeeDelegateInfoCancelled
+ {
+ Caller = Context.Sender,
+ Delegator = delegatorAddress,
+ Delegatee = Address.FromBase58(delegateeAddress),
+ DelegateTransactionList = toCancelTransactionList
+ });
+ }
+ }
+
+ public override GetTransactionFeeDelegateeListOutput GetTransactionFeeDelegateeList(
+ GetTransactionFeeDelegateeListInput input)
+ {
+ Assert(input.DelegatorAddress != null && input.ContractAddress != null && input.MethodName != null,
+ "Invalid input.");
+ var allDelegatees =
+ State.TransactionFeeDelegateInfoMap[input.DelegatorAddress][input.ContractAddress][input.MethodName];
+
+ if (allDelegatees?.Delegatees == null || allDelegatees.Delegatees.Count == 0)
+ {
+ return new GetTransactionFeeDelegateeListOutput();
+ }
+
+ return new GetTransactionFeeDelegateeListOutput
+ {
+ DelegateeAddresses = { allDelegatees.Delegatees.Keys.Select(Address.FromBase58) }
+ };
+ }
+
+ public override TransactionFeeDelegations GetTransactionFeeDelegateInfo(
+ GetTransactionFeeDelegateInfoInput input)
+ {
+ var allDelegatees =
+ State.TransactionFeeDelegateInfoMap[input.DelegatorAddress][input.ContractAddress][input.MethodName];
+ var delegateeAddress = input.DelegateeAddress.ToBase58();
+ // According to protoBuf, return an empty object, but null.
+ if (allDelegatees == null) return new TransactionFeeDelegations();
+
+ var allDelegateesMap = allDelegatees.Delegatees;
+ var result = allDelegateesMap.TryGetValue(delegateeAddress, out var value);
+ return result ? value : new TransactionFeeDelegations();
+ }
}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.MultiToken/TokenContract_Fee_Calculate_Coefficient.cs b/contract/AElf.Contracts.MultiToken/TokenContract_Fee_Calculate_Coefficient.cs
index 8efefd5df0..09e4ebb328 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContract_Fee_Calculate_Coefficient.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContract_Fee_Calculate_Coefficient.cs
@@ -15,6 +15,7 @@ public partial class TokenContract
///
public override Empty UpdateCoefficientsForContract(UpdateCoefficientsInput input)
{
+ Assert(input.Coefficients != null, "Invalid input coefficients.");
Assert(input.Coefficients.FeeTokenType != (int)FeeTypeEnum.Tx, "Invalid fee type.");
AssertDeveloperFeeController();
UpdateCoefficients(input);
@@ -23,6 +24,7 @@ public override Empty UpdateCoefficientsForContract(UpdateCoefficientsInput inpu
public override Empty UpdateCoefficientsForSender(UpdateCoefficientsInput input)
{
+ Assert(input.Coefficients != null, "Invalid input coefficients.");
AssertUserFeeController();
input.Coefficients.FeeTokenType = (int)FeeTypeEnum.Tx; // The only possible for now.
UpdateCoefficients(input);
diff --git a/contract/AElf.Contracts.MultiToken/TokenContract_Fees.cs b/contract/AElf.Contracts.MultiToken/TokenContract_Fees.cs
index da35910cb8..25f853ec11 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContract_Fees.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContract_Fees.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Linq;
using AElf.CSharp.Core;
@@ -7,6 +8,7 @@
using AElf.Standards.ACS12;
using AElf.Types;
using Google.Protobuf;
+using Google.Protobuf.Collections;
using Google.Protobuf.WellKnownTypes;
namespace AElf.Contracts.MultiToken;
@@ -21,11 +23,12 @@ public partial class TokenContract
///
public override ChargeTransactionFeesOutput ChargeTransactionFees(ChargeTransactionFeesInput input)
{
+ Context.LogDebug(() => "ChargeTransactionFees Start");
AssertPermissionAndInput(input);
// Primary token not created yet.
if (State.ChainPrimaryTokenSymbol.Value == null)
{
- return new ChargeTransactionFeesOutput {Success = true};
+ return new ChargeTransactionFeesOutput { Success = true };
}
// Record tx fee bill during current charging process.
@@ -33,7 +36,7 @@ public override ChargeTransactionFeesOutput ChargeTransactionFees(ChargeTransact
var allowanceBill = new TransactionFreeFeeAllowanceBill();
var fromAddress = Context.Sender;
var methodFees = Context.Call(input.ContractAddress, nameof(GetMethodFee),
- new StringValue {Value = input.MethodName});
+ new StringValue { Value = input.MethodName });
var fee = new Dictionary();
var isSizeFeeFree = false;
if (methodFees != null)
@@ -55,7 +58,7 @@ public override ChargeTransactionFeesOutput ChargeUserContractTransactionFees(Ch
// Primary token not created yet.
if (State.ChainPrimaryTokenSymbol.Value == null)
{
- return new ChargeTransactionFeesOutput {Success = true};
+ return new ChargeTransactionFeesOutput { Success = true };
}
// Record tx fee bill during current charging process.
@@ -82,18 +85,43 @@ private ChargeTransactionFeesOutput TryToChargeTransactionFee(ChargeTransactionF
TransactionFeeBill bill, TransactionFreeFeeAllowanceBill allowanceBill, Dictionary fee,
bool isSizeFeeFree)
{
+ Context.LogDebug(() => "TryToChargeTransactionFee Start");
var chargingResult =
ChargeTransactionFeesToBill(input, fromAddress, ref bill, ref allowanceBill, fee, isSizeFeeFree);
if (!chargingResult)
{
+ var delegatorAddress = fromAddress;
chargingResult = ChargeFromDelegations(input, ref fromAddress, ref bill, ref allowanceBill, fee,
- isSizeFeeFree);
+ isSizeFeeFree, delegatorAddress);
+ }
+
+ if (!chargingResult)
+ {
+ var transactionFeeDelegatees =
+ State.TransactionFeeDelegateInfoMap[fromAddress][input.ContractAddress][input.MethodName] ??
+ State.TransactionFeeDelegateesMap[fromAddress];
+ if (transactionFeeDelegatees != null)
+ {
+ var delegateeAddress = transactionFeeDelegatees.Delegatees;
+ foreach (var (delegatee, _) in delegateeAddress)
+ {
+ chargingResult = ChargeFromDelegations(input, ref fromAddress, ref bill, ref allowanceBill, fee,
+ isSizeFeeFree, Address.FromBase58(delegatee));
+ if (chargingResult)
+ {
+ break;
+ }
+ }
+ }
}
ModifyBalance(fromAddress, bill, allowanceBill);
- var chargingOutput = new ChargeTransactionFeesOutput {Success = chargingResult};
+ var chargingOutput = new ChargeTransactionFeesOutput { Success = chargingResult };
if (!chargingResult)
chargingOutput.ChargingInformation = "Transaction fee not enough.";
+
+ Context.LogDebug(() => "TryToChargeTransactionFee End");
+ Context.LogDebug(() => "ChargeTransactionFees End");
return chargingOutput;
}
@@ -120,6 +148,7 @@ private UserContractMethodFees GetActualFee(Address contractAddress, string meth
fee.MergeFrom(spec.Value);
return fee;
}
+
//If special key is null,get the normal fee set by the configuration contract.
//configuration_key:UserContractMethod
var value = State.ConfigurationContract.GetConfiguration.Call(new StringValue
@@ -130,18 +159,28 @@ private UserContractMethodFees GetActualFee(Address contractAddress, string meth
{
return new UserContractMethodFees();
}
+
fee.MergeFrom(value.Value);
return fee;
}
private bool ChargeFromDelegations(ChargeTransactionFeesInput input, ref Address fromAddress,
ref TransactionFeeBill bill, ref TransactionFreeFeeAllowanceBill allowanceBill,
- Dictionary fee, bool isSizeFeeFree)
+ Dictionary fee, bool isSizeFeeFree, Address delegatorAddress)
{
var chargingResult = false;
// Try to charge delegatees
- if (State.TransactionFeeDelegateesMap[fromAddress]?.Delegatees == null) return false;
- foreach (var (delegatee, delegations) in State.TransactionFeeDelegateesMap[fromAddress].Delegatees)
+ // Get delegatee list according to the delegator
+ var delegationInfo =
+ State.TransactionFeeDelegateInfoMap[delegatorAddress][input.ContractAddress][input.MethodName]?.Delegatees ??
+ State.TransactionFeeDelegateesMap[delegatorAddress]?.Delegatees;
+
+ if (delegationInfo == null)
+ {
+ return false;
+ }
+
+ foreach (var (delegatee, delegations) in delegationInfo)
{
// compare current block height with the block height when the delegatee added
if (Context.Transaction.RefBlockNumber < delegations.BlockHeight) continue;
@@ -158,45 +197,48 @@ private bool ChargeFromDelegations(ChargeTransactionFeesInput input, ref Address
allowanceBill = delegateeAllowanceBill;
fromAddress = delegateeAddress;
chargingResult = true;
- ModifyDelegation(delegateeBill, delegateeAllowanceBill, fromAddress);
+ if (!delegations.IsUnlimitedDelegate)
+ {
+ ModifyDelegation(delegateeBill, delegateeAllowanceBill, fromAddress, input.ContractAddress,
+ input.MethodName, delegatorAddress);
+ }
+
break;
}
+
return chargingResult;
}
private void ModifyDelegation(TransactionFeeBill bill, TransactionFreeFeeAllowanceBill allowanceBill,
- Address delegateeAddress)
+ Address delegateeAddress, Address contractAddress, string methodName, Address delegatorAddress)
{
foreach (var (symbol, amount) in bill.FeesMap)
{
- if (amount > 0)
- {
- State.TransactionFeeDelegateesMap[Context.Sender].Delegatees[delegateeAddress.ToBase58()]
- .Delegations[symbol] =
- State.TransactionFeeDelegateesMap[Context.Sender].Delegatees[delegateeAddress.ToBase58()]
- .Delegations[symbol]
- .Sub(amount);
- }
+ if (amount <= 0) continue;
+ var delegateInfo =
+ State.TransactionFeeDelegateInfoMap[delegatorAddress][contractAddress][methodName] ??
+ State.TransactionFeeDelegateesMap[delegatorAddress];
+ delegateInfo.Delegatees[delegateeAddress.ToBase58()].Delegations[symbol] =
+ delegateInfo.Delegatees[delegateeAddress.ToBase58()].Delegations[symbol].Sub(amount);
}
foreach (var (symbol, amount) in allowanceBill.FreeFeeAllowancesMap)
{
- if (amount > 0)
- {
- State.TransactionFeeDelegateesMap[Context.Sender].Delegatees[delegateeAddress.ToBase58()]
- .Delegations[symbol] =
- State.TransactionFeeDelegateesMap[Context.Sender].Delegatees[delegateeAddress.ToBase58()]
- .Delegations[symbol]
- .Sub(amount);
- }
+ if (amount <= 0) continue;
+
+ var delegateInfo =
+ State.TransactionFeeDelegateInfoMap[delegatorAddress][contractAddress][methodName] ??
+ State.TransactionFeeDelegateesMap[delegatorAddress];
+ delegateInfo.Delegatees[delegateeAddress.ToBase58()].Delegations[symbol] =
+ delegateInfo.Delegatees[delegateeAddress.ToBase58()].Delegations[symbol].Sub(amount);
}
}
private void ModifyBalance(Address fromAddress, TransactionFeeBill bill,
TransactionFreeFeeAllowanceBill allowanceBill)
{
- SetOrRefreshMethodFeeFreeAllowances(fromAddress);
- var freeAllowances = CalculateMethodFeeFreeAllowances(fromAddress)?.Clone();
+ SetOrRefreshTransactionFeeFreeAllowances(fromAddress);
+ var freeAllowancesMap = CalculateTransactionFeeFreeAllowances(fromAddress);
// Update balances and allowances
foreach (var (symbol, amount) in bill.FeesMap)
@@ -211,15 +253,15 @@ private void ModifyBalance(Address fromAddress, TransactionFeeBill bill,
});
}
+ if (freeAllowancesMap.Map == null || freeAllowancesMap.Map.Count == 0) return;
+
foreach (var (symbol, amount) in allowanceBill.FreeFeeAllowancesMap)
{
if (amount > 0)
{
- ModifyFreeFeeAllowanceAmount(freeAllowances, symbol, -amount);
+ ModifyFreeFeeAllowanceAmount(fromAddress, freeAllowancesMap, symbol, -amount);
}
}
-
- State.MethodFeeFreeAllowancesMap[fromAddress] = freeAllowances;
}
private bool ChargeTransactionFeesToBill(ChargeTransactionFeesInput input, Address fromAddress,
@@ -229,14 +271,20 @@ private bool ChargeTransactionFeesToBill(ChargeTransactionFeesInput input, Addre
{
var successToChargeBaseFee = true;
- SetOrRefreshMethodFeeFreeAllowances(fromAddress);
- var freeAllowances = CalculateMethodFeeFreeAllowances(fromAddress)?.Clone();
+ SetOrRefreshTransactionFeeFreeAllowances(fromAddress);
+ var freeAllowancesMap = CalculateTransactionFeeFreeAllowances(fromAddress);
if (fee.Count != 0)
{
// If base fee is set before, charge base fee.
successToChargeBaseFee =
- ChargeBaseFee(fee, fromAddress, ref bill, freeAllowances, ref allowanceBill, delegations);
+ ChargeBaseFee(fee, fromAddress, ref bill, freeAllowancesMap, ref allowanceBill, delegations);
+ }
+
+ //For delegation, if the base fee fails to be charged, the size fee will not be charged
+ if (delegations != null && !successToChargeBaseFee)
+ {
+ return false;
}
var successToChargeSizeFee = true;
@@ -244,28 +292,30 @@ private bool ChargeTransactionFeesToBill(ChargeTransactionFeesInput input, Addre
{
// If IsSizeFeeFree == true, do not charge size fee.
successToChargeSizeFee =
- ChargeSizeFee(input, fromAddress, ref bill, freeAllowances, ref allowanceBill, delegations);
+ ChargeSizeFee(input, fromAddress, ref bill, freeAllowancesMap, ref allowanceBill, delegations);
}
return successToChargeBaseFee && successToChargeSizeFee;
}
- private void SetOrRefreshMethodFeeFreeAllowances(Address address)
+ private void SetOrRefreshTransactionFeeFreeAllowances(Address address)
{
- var config = State.MethodFeeFreeAllowancesConfig.Value;
- if (config == null || State.Balances[address][Context.Variables.NativeSymbol] < config.Threshold)
- {
- return;
- }
+ var config = State.TransactionFeeFreeAllowancesSymbolList.Value;
+ if (config == null) return;
- var lastRefreshTime = State.MethodFeeFreeAllowancesLastRefreshTimeMap[address];
- if (lastRefreshTime != null && config.RefreshSeconds > (Context.CurrentBlockTime - lastRefreshTime).Seconds)
+ foreach (var symbol in config.Symbols)
{
- return;
- }
+ if (State.Balances[address][symbol] <
+ State.TransactionFeeFreeAllowancesConfigMap[symbol].Threshold) continue;
+ var lastRefreshTime = State.TransactionFeeFreeAllowancesLastRefreshTimes[address][symbol];
+
+ if (lastRefreshTime != null && State.TransactionFeeFreeAllowancesConfigMap[symbol].RefreshSeconds >
+ (Context.CurrentBlockTime - lastRefreshTime).Seconds) continue;
- State.MethodFeeFreeAllowancesLastRefreshTimeMap[address] = Context.CurrentBlockTime;
- State.MethodFeeFreeAllowancesMap[address] = config.FreeAllowances;
+ State.TransactionFeeFreeAllowancesLastRefreshTimes[address][symbol] = Context.CurrentBlockTime;
+ State.TransactionFeeFreeAllowances[address][symbol] =
+ State.TransactionFeeFreeAllowancesConfigMap[symbol].FreeAllowances.Clone();
+ }
}
private Dictionary GetBaseFeeDictionary(MethodFees methodFees)
@@ -283,12 +333,15 @@ private Dictionary GetUserContractFeeDictionary(UserContractMethod
}
private bool ChargeBaseFee(Dictionary methodFeeMap, Address fromAddress, ref TransactionFeeBill bill,
- MethodFeeFreeAllowances freeAllowances, ref TransactionFreeFeeAllowanceBill allowanceBill,
+ TransactionFeeFreeAllowancesMap transactionFeeFreeAllowancesMap,
+ ref TransactionFreeFeeAllowanceBill allowanceBill,
TransactionFeeDelegations delegations = null)
{
+ Context.LogDebug(() => "ChargeBaseFee Start");
// Fail to charge
if (!ChargeFirstSufficientToken(methodFeeMap, fromAddress, out var symbolToChargeBaseFee,
- out var amountToChargeBaseFee, out var existingBalance, out var existingAllowance, freeAllowances,
+ out var amountToChargeBaseFee, out var existingBalance, out var existingAllowance,
+ transactionFeeFreeAllowancesMap,
delegations))
{
Context.LogDebug(() => "Failed to charge first sufficient token.");
@@ -314,18 +367,80 @@ private bool ChargeBaseFee(Dictionary methodFeeMap, Address fromAd
bill.FeesMap.Add(symbolToChargeBaseFee, amountToChargeBaseFee.Sub(existingAllowance));
}
+ Context.LogDebug(() => "ChargeBaseFee End");
return true;
}
private bool ChargeSizeFee(ChargeTransactionFeesInput input, Address fromAddress, ref TransactionFeeBill bill,
- MethodFeeFreeAllowances freeAllowances, ref TransactionFreeFeeAllowanceBill allowanceBill,
+ TransactionFeeFreeAllowancesMap transactionFeeFreeAllowancesMap,
+ ref TransactionFreeFeeAllowanceBill allowanceBill,
TransactionFeeDelegations delegations = null)
{
- string symbolChargedForBaseFee = null;
- var amountChargedForBaseFee = 0L;
- var amountChargedForBaseAllowance = 0L;
- // Size Fee is charged in primary token, aelf.
+
+ Context.LogDebug(() => "ChargeSizeFee Start");
+
+ //If delegation != null,from address->delegateeAddress
+ // Size Fee is charged in primary token, elf.
var symbolToPayTxFee = State.ChainPrimaryTokenSymbol.Value;
+ //Get primary token balance
+ GetAvailableBalance(symbolToPayTxFee, fromAddress, bill, transactionFeeFreeAllowancesMap, allowanceBill,
+ out var symbolChargedForBaseFee, out var amountChargedForBaseFee, out var amountChargedForBaseAllowance,
+ out var availableBalance, out var availableAllowance);
+ var txSizeFeeAmount = input.TransactionSizeFee;
+
+ // SymbolsToPayTxSizeFee is set of all available token can be charged, and with the ratio of primary token and another.
+ if (input.SymbolsToPayTxSizeFee.Any())
+ {
+ var allSymbolToTxFee = input.SymbolsToPayTxSizeFee.ToList();
+ var availableSymbol = GetAvailableSymbolToPayTxFee(allSymbolToTxFee, fromAddress, txSizeFeeAmount,
+ transactionFeeFreeAllowancesMap, symbolChargedForBaseFee, amountChargedForBaseFee,
+ amountChargedForBaseAllowance, delegations);
+
+ if (availableSymbol != null && availableSymbol.TokenSymbol != symbolToPayTxFee)
+ {
+ symbolToPayTxFee = availableSymbol.TokenSymbol;
+ txSizeFeeAmount = txSizeFeeAmount.Mul(availableSymbol.AddedTokenWeight)
+ .Div(availableSymbol.BaseTokenWeight);
+ GetAvailableBalance(symbolToPayTxFee, fromAddress, bill, transactionFeeFreeAllowancesMap, allowanceBill,
+ out symbolChargedForBaseFee, out amountChargedForBaseFee, out amountChargedForBaseAllowance,
+ out availableBalance, out availableAllowance);
+ }
+
+ //For delegation,if there is no available token,return false,no need to generate bill
+ if (delegations != null && availableSymbol == null)
+ {
+ return false;
+ }
+ }
+
+ var chargeResult = availableBalance.Add(availableAllowance) >= txSizeFeeAmount;
+ if (delegations != null)
+ {
+ chargeResult = chargeResult && IsDelegationEnough(symbolToPayTxFee, symbolChargedForBaseFee,
+ amountChargedForBaseFee.Add(amountChargedForBaseAllowance), txSizeFeeAmount, delegations);
+ if (!chargeResult)
+ {
+ return false;
+ }
+ }
+
+ GenerateBill(txSizeFeeAmount, symbolToPayTxFee, symbolChargedForBaseFee, availableBalance, availableAllowance,
+ ref bill, ref allowanceBill);
+
+ Context.LogDebug(() => "ChargeSizeFee End");
+
+ return chargeResult;
+ }
+
+ private void GetAvailableBalance(string symbolToPayTxFee, Address fromAddress, TransactionFeeBill bill,
+ TransactionFeeFreeAllowancesMap transactionFeeFreeAllowancesMap, TransactionFreeFeeAllowanceBill allowanceBill,
+ out string symbolChargedForBaseFee, out long amountChargedForBaseFee, out long amountChargedForBaseAllowance,
+ out long availableBalance, out long availableAllowance)
+ {
+ symbolChargedForBaseFee = null;
+ amountChargedForBaseFee = 0L;
+ amountChargedForBaseAllowance = 0L;
+
if (bill.FeesMap.Any())
{
symbolChargedForBaseFee = bill.FeesMap.First().Key;
@@ -333,92 +448,98 @@ private bool ChargeSizeFee(ChargeTransactionFeesInput input, Address fromAddress
amountChargedForBaseAllowance = allowanceBill.FreeFeeAllowancesMap[symbolChargedForBaseFee];
}
- var availableBalance = symbolChargedForBaseFee == symbolToPayTxFee
+ availableBalance = symbolChargedForBaseFee == symbolToPayTxFee
// Available balance need to deduct amountChargedForBaseFee, if base fee is charged in the same token.
? GetBalance(fromAddress, symbolToPayTxFee).Sub(amountChargedForBaseFee)
: GetBalance(fromAddress, symbolToPayTxFee);
- var availableAllowance = symbolChargedForBaseFee == symbolToPayTxFee
- ? GetFreeFeeAllowanceAmount(freeAllowances, symbolToPayTxFee).Sub(amountChargedForBaseAllowance)
- : GetFreeFeeAllowanceAmount(freeAllowances, symbolToPayTxFee);
- var txSizeFeeAmount = input.TransactionSizeFee;
+ availableAllowance = symbolChargedForBaseFee == symbolToPayTxFee
+ ? GetFreeFeeAllowanceAmount(transactionFeeFreeAllowancesMap, symbolToPayTxFee)
+ .Sub(amountChargedForBaseAllowance)
+ : GetFreeFeeAllowanceAmount(transactionFeeFreeAllowancesMap, symbolToPayTxFee);
+ }
+ private SymbolToPayTxSizeFee GetAvailableSymbolToPayTxFee(List allSymbolToTxFee,
+ Address fromAddress, long txSizeFeeAmount, TransactionFeeFreeAllowancesMap transactionFeeFreeAllowancesMap,
+ string symbolChargedForBaseFee, long amountChargedForBaseFee, long amountChargedForBaseAllowance,
+ TransactionFeeDelegations delegations = null)
+ {
+ SymbolToPayTxSizeFee availableSymbol = null;
+ SymbolToPayTxSizeFee availableSymbolWithAnything = null;
+ SymbolToPayTxSizeFee availableSymbolWithEnoughBalance = null;
+ SymbolToPayTxSizeFee availableSymbolWithEnoughBalancePlusAllowance = null;
- // SymbolsToPayTxSizeFee is set of all available token can be charged, and with the ratio of primary token and another.
- if (input.SymbolsToPayTxSizeFee.Any())
+ // get 1st Allowance > size fee, else, get 1st Balance + Allowance > 0, else get 1st > 0
+ foreach (var symbolToPlayTxSizeFee in allSymbolToTxFee)
{
- var allSymbolToTxFee = input.SymbolsToPayTxSizeFee;
- // get 1st Balance + Allowance > size fee, else, get 1st > 0
- var availableSymbol = allSymbolToTxFee.FirstOrDefault(x =>
- GetBalancePlusAllowanceCalculatedBaseOnPrimaryToken(fromAddress, x, symbolChargedForBaseFee,
- amountChargedForBaseFee, freeAllowances, amountChargedForBaseAllowance) >= txSizeFeeAmount &&
- IsDelegationEnoughBaseOnPrimaryToken(x, symbolChargedForBaseFee,
- amountChargedForBaseFee.Add(amountChargedForBaseAllowance), txSizeFeeAmount, delegations));
+ if (delegations != null)
+ {
+ var delegationEnough = IsDelegationEnoughBaseOnPrimaryToken(symbolToPlayTxSizeFee,
+ symbolChargedForBaseFee, amountChargedForBaseFee.Add(amountChargedForBaseAllowance),
+ txSizeFeeAmount, delegations);
+ if (!delegationEnough) break;
+ }
- if (delegations != null && availableSymbol == null)
+ var allowance = GetAllowanceCalculatedBaseOnPrimaryToken(symbolToPlayTxSizeFee,
+ transactionFeeFreeAllowancesMap, symbolChargedForBaseFee, amountChargedForBaseAllowance);
+ var balance = GetBalanceCalculatedBaseOnPrimaryToken(fromAddress, symbolToPlayTxSizeFee,
+ symbolChargedForBaseFee, amountChargedForBaseFee);
+
+ var balancePlusAllowance = balance.Add(allowance);
+
+ if (allowance >= txSizeFeeAmount)
{
- return false;
+ availableSymbol = symbolToPlayTxSizeFee;
+ break;
}
- if (delegations == null)
+ if (delegations == null && balancePlusAllowance > 0)
{
- availableSymbol ??= allSymbolToTxFee.FirstOrDefault(x =>
- GetBalancePlusAllowanceCalculatedBaseOnPrimaryToken(fromAddress, x, symbolChargedForBaseFee,
- amountChargedForBaseFee, freeAllowances, amountChargedForBaseAllowance) > 0);
+ availableSymbolWithAnything ??= symbolToPlayTxSizeFee;
}
- if (availableSymbol != null && availableSymbol.TokenSymbol != symbolToPayTxFee)
+ if (balancePlusAllowance < txSizeFeeAmount) continue;
+
+ if (allowance > 0)
{
- symbolToPayTxFee = availableSymbol.TokenSymbol;
- txSizeFeeAmount = txSizeFeeAmount.Mul(availableSymbol.AddedTokenWeight)
- .Div(availableSymbol.BaseTokenWeight);
- availableBalance = symbolChargedForBaseFee == symbolToPayTxFee
- ? GetBalance(fromAddress, symbolToPayTxFee).Sub(amountChargedForBaseFee)
- : GetBalance(fromAddress, symbolToPayTxFee);
- availableAllowance = symbolChargedForBaseFee == symbolToPayTxFee
- ? GetFreeFeeAllowanceAmount(freeAllowances, symbolToPayTxFee).Sub(amountChargedForBaseAllowance)
- : GetFreeFeeAllowanceAmount(freeAllowances, symbolToPayTxFee);
+ availableSymbolWithEnoughBalancePlusAllowance ??= symbolToPlayTxSizeFee;
+ }
+ else
+ {
+ availableSymbolWithEnoughBalance ??= symbolToPlayTxSizeFee;
}
}
- // Default token is primary token, so if no token can be charged in input.SymbolsToPayTxSizeFee, primary token will be the last one.
- // So, we have to take primary token delegation quota into account.
+ availableSymbol ??= availableSymbolWithEnoughBalancePlusAllowance ??
+ availableSymbolWithEnoughBalance ?? availableSymbolWithAnything;
+
+ return availableSymbol;
+ }
- // start to charge
+ private void GenerateBill(long txSizeFeeAmount, string symbolToPayTxFee, string symbolChargedForBaseFee,
+ long availableBalance, long availableAllowance, ref TransactionFeeBill bill,
+ ref TransactionFreeFeeAllowanceBill allowanceBill)
+ {
var chargeAmount = 0L;
var chargeAllowanceAmount = 0L;
-
- if (delegations == null
- || (delegations.Delegations.Keys.Contains(symbolToPayTxFee)
- && (symbolChargedForBaseFee == symbolToPayTxFee
- ? delegations.Delegations[symbolToPayTxFee]
- .Sub(amountChargedForBaseFee.Add(amountChargedForBaseAllowance))
- : delegations.Delegations[symbolToPayTxFee]) >= txSizeFeeAmount))
+ if (availableBalance.Add(availableAllowance) > txSizeFeeAmount)
{
- // Balance + Allowance > size fee
- if (availableBalance.Add(availableAllowance) > txSizeFeeAmount)
+ // Allowance > size fee, all allowance
+ if (availableAllowance > txSizeFeeAmount)
{
- // Allowance > size fee, all allowance
- if (availableAllowance > txSizeFeeAmount)
- {
- chargeAllowanceAmount = txSizeFeeAmount;
- }
- else
- {
- // Allowance is not enough
- chargeAllowanceAmount = availableAllowance;
- chargeAmount = txSizeFeeAmount.Sub(chargeAllowanceAmount);
- }
+ chargeAllowanceAmount = txSizeFeeAmount;
}
else
{
+ // Allowance is not enough
chargeAllowanceAmount = availableAllowance;
- chargeAmount = availableBalance;
+ chargeAmount = txSizeFeeAmount.Sub(chargeAllowanceAmount);
}
}
-
- // Warning, currently, if the delegation quato is not enough, we will not charge delegatee bill, so we don't calculate it now.
- if (delegations == null && symbolToPayTxFee == null)
- return availableBalance.Add(availableAllowance) >= txSizeFeeAmount;
+ else
+ {
+ chargeAllowanceAmount = availableAllowance;
+ chargeAmount = availableBalance;
+ }
if (symbolChargedForBaseFee == symbolToPayTxFee)
{
@@ -439,20 +560,6 @@ private bool ChargeSizeFee(ChargeTransactionFeesInput input, Address fromAddress
allowanceBill.FreeFeeAllowancesMap.Add(symbolToPayTxFee, chargeAllowanceAmount);
}
}
-
- if (delegations == null
- || (delegations.Delegations.Keys.Contains(symbolToPayTxFee)
- && (symbolChargedForBaseFee == symbolToPayTxFee
- ? delegations.Delegations[symbolToPayTxFee]
- .Sub(amountChargedForBaseFee.Add(amountChargedForBaseAllowance))
- : delegations.Delegations[symbolToPayTxFee]) >= txSizeFeeAmount))
- {
- return availableBalance.Add(availableAllowance) >= txSizeFeeAmount;
- }
- else
- {
- return false;
- }
}
public override Empty ChargeResourceToken(ChargeResourceTokenInput input)
@@ -591,72 +698,170 @@ public override Empty SetSymbolsToPayTxSizeFee(SymbolListToPayTxSizeFee input)
///
///
///
- ///
+ ///
///
///
private bool ChargeFirstSufficientToken(Dictionary symbolToAmountMap, Address fromAddress,
- out string symbol,
- out long amount, out long existingBalance, out long existingAllowance, MethodFeeFreeAllowances freeAllowances,
- TransactionFeeDelegations delegations = null)
+ out string symbol, out long amount, out long existingBalance, out long existingAllowance,
+ TransactionFeeFreeAllowancesMap transactionFeeFreeAllowancesMap, TransactionFeeDelegations delegations = null)
{
symbol = null;
amount = 0L;
existingBalance = 0L;
existingAllowance = 0L;
+ bool chargeResult;
+
+ if (delegations != null)
+ {
+ //from address -> delegatee
+ chargeResult = TryToChargeDelegateBaseFee(symbolToAmountMap, fromAddress, transactionFeeFreeAllowancesMap,
+ delegations, out amount, out symbol, out existingBalance, out existingAllowance);
+ return chargeResult;
+ }
- //var fromAddress = Context.Sender;
- string symbolOfValidBalance = null;
+ chargeResult = TryToChargeUserBaseFee(symbolToAmountMap, fromAddress, transactionFeeFreeAllowancesMap,
+ out amount, out symbol, out existingBalance, out existingAllowance);
- // Traverse available token symbols, check balance one by one
- // until there's balance of one certain token is enough to pay the fee.
- foreach (var symbolToAmount in symbolToAmountMap)
+ if (symbol != null)
+ {
+ existingBalance = GetBalance(fromAddress, symbol);
+ existingAllowance = GetFreeFeeAllowanceAmount(transactionFeeFreeAllowancesMap, symbol);
+ amount = symbolToAmountMap[symbol];
+ }
+
+ //For user, if charge failed and delegation is null, priority charge primary token
+ if (!chargeResult)
+ {
+ var primaryTokenSymbol = GetPrimaryTokenSymbol(new Empty()).Value;
+ if (symbolToAmountMap.ContainsKey(primaryTokenSymbol))
+ {
+ symbol = primaryTokenSymbol;
+ existingBalance = GetBalance(fromAddress, symbol);
+ existingAllowance = GetFreeFeeAllowanceAmount(transactionFeeFreeAllowancesMap, symbol);
+ }
+ }
+
+ return chargeResult;
+ }
+
+ private bool TryToChargeUserBaseFee(Dictionary symbolToAmountMap, Address fromAddress,
+ TransactionFeeFreeAllowancesMap transactionFeeFreeAllowancesMap, out long amount,
+ out string symbolOfValidBalance, out long existingBalance, out long existingAllowance)
+ {
+ // priority: enough allowance -> symbolWithEnoughBalancePlusAllowance -> symbolWithEnoughBalance -> symbolWithAnything
+ symbolOfValidBalance = null;
+ string symbolWithAnything = null;
+ string symbolWithEnoughBalance = null;
+ string symbolWithEnoughBalancePlusAllowance = null;
+
+ amount = 0;
+ existingBalance = 0;
+ existingAllowance = 0;
+ //For user
+ //Find the token that satisfies the balance of the fee,if there is no token that satisfies the balance of the fee, find the token that balance > 0
+ foreach (var (symbol, value) in symbolToAmountMap)
{
// current token symbol
- existingBalance = GetBalance(fromAddress, symbolToAmount.Key);
- symbol = symbolToAmount.Key;
- amount = symbolToAmount.Value;
+ amount = value;
+ existingBalance = GetBalance(fromAddress, symbol);
+ existingAllowance = GetFreeFeeAllowanceAmount(transactionFeeFreeAllowancesMap, symbol);
- // free allowance in current token symbol
- existingAllowance = GetFreeFeeAllowanceAmount(freeAllowances, symbol);
+ var existingBalancePlusAllowance = existingBalance.Add(existingAllowance);
- // if delegations is null, that means no delegation is involved.
- if (delegations == null
- || (delegations.Delegations.ContainsKey(symbol) && delegations.Delegations[symbol] >= amount))
+
+ // allowance is enough to cover the base fee
+ if (existingAllowance >= amount)
{
- if (existingBalance.Add(existingAllowance) > 0)
- {
- symbolOfValidBalance = symbol;
- }
+ symbolOfValidBalance = symbol;
+ return true;
+ }
- if (existingBalance.Add(existingAllowance) >= amount) break;
+ if (existingBalancePlusAllowance <= 0) continue;
+
+ // find symbol: balance + allowance > 0
+ symbolWithAnything ??= symbol;
+
+ if (existingBalancePlusAllowance < amount) continue;
+
+ if (existingAllowance > 0)
+ {
+ // find symbol: balance plus allowance is enough to cover the base fee and allowance is greater than 0
+ symbolWithEnoughBalancePlusAllowance ??= symbol;
+ }
+ else
+ {
+ // find symbol: balance is enough to cover the base fee and no allowance
+ symbolWithEnoughBalance ??= symbol;
}
}
- if (delegations == null
- || (symbolOfValidBalance != null && delegations.Delegations.ContainsKey(symbolOfValidBalance) &&
- delegations.Delegations[symbolOfValidBalance] >= amount))
+ if (symbolWithEnoughBalancePlusAllowance == null && symbolWithEnoughBalance == null)
{
- if (existingBalance.Add(existingAllowance) >= amount) return true;
- }
+ symbolOfValidBalance = symbolWithAnything;
- var primaryTokenSymbol = GetPrimaryTokenSymbol(new Empty()).Value;
- if (symbolToAmountMap.Keys.Contains(primaryTokenSymbol) && delegations == null)
- {
- symbol = primaryTokenSymbol;
- existingBalance = GetBalance(fromAddress, primaryTokenSymbol);
- existingAllowance = GetFreeFeeAllowanceAmount(freeAllowances, symbol);
+ return false;
}
- else
+
+ symbolOfValidBalance = symbolWithEnoughBalancePlusAllowance ?? symbolWithEnoughBalance;
+
+ return true;
+ }
+
+ private bool TryToChargeDelegateBaseFee(Dictionary symbolToAmountMap, Address fromAddress,
+ TransactionFeeFreeAllowancesMap transactionFeeFreeAllowancesMap, TransactionFeeDelegations delegations,
+ out long amount, out string symbolOfValidBalance, out long existingBalance, out long existingAllowance)
+ {
+ symbolOfValidBalance = null;
+ amount = 0;
+ existingBalance = 0;
+ existingAllowance = 0;
+ string symbolWithEnoughBalance = null;
+ string symbolWithEnoughBalancePlusAllowance = null;
+
+ //Find the token that satisfies the delegate limit and satisfies the balance of the fee
+ foreach (var (symbol, value) in symbolToAmountMap)
{
- symbol = symbolOfValidBalance;
- if (symbol != null)
+ // current token symbol
+ amount = value;
+ existingBalance = GetBalance(fromAddress, symbol);
+ existingAllowance = GetFreeFeeAllowanceAmount(transactionFeeFreeAllowancesMap, symbol);
+ // is unlimited delegate is true || is unlimited delegate is false and delegation is enough
+ if (delegations.IsUnlimitedDelegate || (!delegations.IsUnlimitedDelegate &&
+ delegations.Delegations.ContainsKey(symbol) &&
+ delegations.Delegations[symbol] >= amount))
{
- existingBalance = GetBalance(fromAddress, symbolOfValidBalance);
- existingAllowance = GetFreeFeeAllowanceAmount(freeAllowances, symbol);
+ //If allowance is enough,return true
+ if (existingAllowance >= amount)
+ {
+ symbolOfValidBalance = symbol;
+ return true;
+ }
+
+ //Find symbol which balance+allowance >= amount
+ if (existingBalance.Add(existingAllowance) < amount) continue;
+
+ if (existingAllowance > 0)
+ {
+ //If balance+allowance is enough,priority find the symbol which allowance > 0
+ symbolWithEnoughBalancePlusAllowance ??= symbol;
+ }
+ else
+ {
+ symbolWithEnoughBalance ??= symbol;
+ }
}
}
- return false;
+ symbolOfValidBalance = symbolWithEnoughBalancePlusAllowance ?? symbolWithEnoughBalance;
+
+ if (symbolOfValidBalance != null)
+ {
+ existingBalance = GetBalance(fromAddress, symbolOfValidBalance);
+ existingAllowance = GetFreeFeeAllowanceAmount(transactionFeeFreeAllowancesMap, symbolOfValidBalance);
+ amount = symbolToAmountMap[symbolOfValidBalance];
+ }
+
+ return symbolOfValidBalance != null;
}
public override Empty ClaimTransactionFees(TotalTransactionFeesMap input)
@@ -674,6 +879,13 @@ public override Empty ClaimTransactionFees(TotalTransactionFeesMap input)
var symbol = bill.Key;
var amount = bill.Value;
ModifyBalance(Context.Self, symbol, amount);
+ Context.Fire(new TransactionFeeClaimed
+ {
+ Symbol = symbol,
+ Amount = amount,
+ Receiver = Context.Self
+ });
+
TransferTransactionFeesToFeeReceiver(symbol, amount);
}
@@ -772,11 +984,12 @@ private void PayResourceTokens(TotalResourceTokensMaps billMaps, bool isMainChai
if (amount > 0)
{
ModifyBalance(bill.ContractAddress, symbol, -amount);
+ var receiver = Context.Self;
if (isMainChain)
{
Context.LogDebug(() => $"Adding {amount} of {symbol}s to dividend pool.");
// Main Chain.
- ModifyBalance(Context.Self, symbol, amount);
+ ModifyBalance(receiver, symbol, amount);
State.DividendPoolContract.Donate.Send(new DonateInput
{
Symbol = symbol,
@@ -787,10 +1000,17 @@ private void PayResourceTokens(TotalResourceTokensMaps billMaps, bool isMainChai
{
Context.LogDebug(() => $"Adding {amount} of {symbol}s to consensus address account.");
// Side Chain
- var consensusContractAddress =
+ receiver =
Context.GetContractAddressByName(SmartContractConstants.ConsensusContractSystemName);
- ModifyBalance(consensusContractAddress, symbol, amount);
+ ModifyBalance(receiver, symbol, amount);
}
+ Context.Fire(new ResourceTokenClaimed
+ {
+ Symbol = symbol,
+ Amount = amount,
+ Payer = bill.ContractAddress,
+ Receiver = receiver
+ });
}
}
}
@@ -815,7 +1035,7 @@ private void PayRental()
}
// Update LastPayRentTime if it is ready to charge rental.
- State.LastPayRentTime.Value += new Duration {Seconds = duration.Mul(60)};
+ State.LastPayRentTime.Value += new Duration { Seconds = duration.Mul(60) };
foreach (var symbol in Context.Variables.GetStringArray(TokenContractConstants.PayRentalSymbolListName))
{
@@ -869,7 +1089,9 @@ private void PayRental()
Context.Fire(new RentalCharged()
{
Symbol = symbol,
- Amount = donates
+ Amount = donates,
+ Payer = creator,
+ Receiver = consensusContractAddress
});
}
}
@@ -999,55 +1221,138 @@ public override Address GetFeeReceiver(Empty input)
return State.FeeReceiver.Value;
}
- public override Empty ConfigMethodFeeFreeAllowances(MethodFeeFreeAllowancesConfig input)
+ public override Empty ConfigTransactionFeeFreeAllowances(ConfigTransactionFeeFreeAllowancesInput input)
+ {
+ AssertSenderAddressWith(GetDefaultParliamentController().OwnerAddress);
+ Assert(input.Value != null && input.Value.Count > 0, "Invalid input");
+
+ State.TransactionFeeFreeAllowancesSymbolList.Value ??= new TransactionFeeFreeAllowancesSymbolList
+ {
+ Symbols = { new RepeatedField() }
+ };
+
+ foreach (var allowances in input.Value!)
+ {
+ ValidateToken(allowances.Symbol);
+ Assert(
+ allowances.TransactionFeeFreeAllowances?.Value != null &&
+ allowances.TransactionFeeFreeAllowances.Value.Count > 0,
+ "Invalid input allowances");
+ Assert(allowances.Threshold >= 0, "Invalid input threshold");
+ Assert(allowances.RefreshSeconds >= 0, "Invalid input refresh seconds");
+
+ var config = new TransactionFeeFreeAllowanceConfig
+ {
+ Symbol = allowances.Symbol,
+ Threshold = allowances.Threshold,
+ RefreshSeconds = allowances.RefreshSeconds,
+ FreeAllowances = new TransactionFeeFreeAllowanceMap()
+ };
+
+ foreach (var allowance in allowances.TransactionFeeFreeAllowances!.Value!)
+ {
+ config.FreeAllowances.Map.TryAdd(allowance.Symbol, allowance);
+ }
+
+ State.TransactionFeeFreeAllowancesConfigMap[allowances.Symbol] = config;
+
+ if (!State.TransactionFeeFreeAllowancesSymbolList.Value.Symbols.Contains(allowances.Symbol))
+ {
+ State.TransactionFeeFreeAllowancesSymbolList.Value.Symbols.Add(allowances.Symbol);
+ }
+ }
+
+ return new Empty();
+ }
+
+ private void ValidateToken(string symbol)
+ {
+ Assert(!string.IsNullOrWhiteSpace(symbol), "Invalid input symbol");
+ Assert(State.TokenInfos[symbol] != null, $"Symbol {symbol} not exist");
+ }
+
+ public override Empty RemoveTransactionFeeFreeAllowancesConfig(RemoveTransactionFeeFreeAllowancesConfigInput input)
{
AssertSenderAddressWith(GetDefaultParliamentController().OwnerAddress);
- State.MethodFeeFreeAllowancesConfig.Value = input;
+ Assert(input.Symbols != null && input.Symbols.Count > 0, "Invalid input");
+ Assert(State.TransactionFeeFreeAllowancesSymbolList.Value != null, "Method fee free allowances config not set");
+
+ var symbols = input.Symbols!.Distinct();
+
+ foreach (var symbol in symbols)
+ {
+ if (State.TransactionFeeFreeAllowancesSymbolList.Value!.Symbols.Contains(symbol))
+ {
+ State.TransactionFeeFreeAllowancesSymbolList.Value.Symbols.Remove(symbol);
+ }
+ }
+
return new Empty();
}
- public override MethodFeeFreeAllowancesConfig GetMethodFeeFreeAllowancesConfig(Empty input)
+ public override GetTransactionFeeFreeAllowancesConfigOutput GetTransactionFeeFreeAllowancesConfig(Empty input)
{
- return State.MethodFeeFreeAllowancesConfig.Value;
+ var symbols = State.TransactionFeeFreeAllowancesSymbolList.Value?.Symbols;
+ if (symbols == null) return new GetTransactionFeeFreeAllowancesConfigOutput();
+
+ var output = new GetTransactionFeeFreeAllowancesConfigOutput();
+
+ foreach (var symbol in symbols)
+ {
+ output.Value.Add(State.TransactionFeeFreeAllowancesConfigMap[symbol]);
+ }
+
+ return output;
}
- public override MethodFeeFreeAllowances GetMethodFeeFreeAllowances(Address input)
+ public override TransactionFeeFreeAllowancesMap GetTransactionFeeFreeAllowances(Address input)
{
- return CalculateMethodFeeFreeAllowances(input);
+ return CalculateTransactionFeeFreeAllowances(input);
}
- private MethodFeeFreeAllowances CalculateMethodFeeFreeAllowances(Address input)
+ private TransactionFeeFreeAllowancesMap CalculateTransactionFeeFreeAllowances(Address input)
{
- var freeAllowances = State.MethodFeeFreeAllowancesMap[input];
- var freeAllowancesConfig = State.MethodFeeFreeAllowancesConfig.Value;
+ var freeAllowanceMap = State.TransactionFeeFreeAllowances[input];
+
+ var freeAllowancesConfig = State.TransactionFeeFreeAllowancesSymbolList.Value;
if (freeAllowancesConfig == null)
{
- return new MethodFeeFreeAllowances();
+ return new TransactionFeeFreeAllowancesMap();
}
- var config = freeAllowancesConfig.Clone();
+ var transactionFeeFreeAllowancesMap = new TransactionFeeFreeAllowancesMap();
+
+ foreach (var symbol in freeAllowancesConfig.Symbols)
+ {
+ var balance = State.Balances[input][symbol];
+ if (balance < State.TransactionFeeFreeAllowancesConfigMap[symbol].Threshold) continue;
- var balance = State.Balances[input][Context.Variables.NativeSymbol];
- if (balance < config.Threshold) return new MethodFeeFreeAllowances();
+ var lastRefreshTime = State.TransactionFeeFreeAllowancesLastRefreshTimes[input][symbol];
- var lastRefreshTime = State.MethodFeeFreeAllowancesLastRefreshTimeMap[input];
+ var freeAllowances = freeAllowanceMap[symbol];
- if (freeAllowances == null)
- {
- if (balance >= config.Threshold)
+ if (freeAllowances == null)
{
- return new MethodFeeFreeAllowances {Value = {config.FreeAllowances.Value}};
+ transactionFeeFreeAllowancesMap.Map.Add(symbol,
+ State.TransactionFeeFreeAllowancesConfigMap[symbol].FreeAllowances.Clone());
+ continue;
}
- }
- if (lastRefreshTime == null)
- {
- return freeAllowances;
+ if (lastRefreshTime == null)
+ {
+ transactionFeeFreeAllowancesMap.Map.Add(symbol, freeAllowances);
+ }
+ else
+ {
+ transactionFeeFreeAllowancesMap.Map[symbol] =
+ (Context.CurrentBlockTime - lastRefreshTime).Seconds >
+ State.TransactionFeeFreeAllowancesConfigMap[symbol].RefreshSeconds
+ ? State.TransactionFeeFreeAllowancesConfigMap[symbol].FreeAllowances.Clone()
+ : freeAllowances;
+ }
}
- return (Context.CurrentBlockTime - lastRefreshTime).Seconds > config.RefreshSeconds
- ? new MethodFeeFreeAllowances {Value = {config.FreeAllowances.Value}}
- : freeAllowances;
+ return transactionFeeFreeAllowancesMap;
}
private long GetBalanceCalculatedBaseOnPrimaryToken(Address fromAddress, SymbolToPayTxSizeFee tokenInfo,
@@ -1063,18 +1368,19 @@ private long GetBalanceCalculatedBaseOnPrimaryToken(Address fromAddress, SymbolT
private long GetBalancePlusAllowanceCalculatedBaseOnPrimaryToken(Address fromAddress,
SymbolToPayTxSizeFee tokenInfo, string baseSymbol,
- long cost, MethodFeeFreeAllowances freeAllowances, long allowanceCost)
+ long cost, TransactionFeeFreeAllowancesMap transactionFeeFreeAllowancesMap, long allowanceCost)
{
return GetBalanceCalculatedBaseOnPrimaryToken(fromAddress, tokenInfo, baseSymbol, cost).Add(
- GetAllowanceCalculatedBaseOnPrimaryToken(tokenInfo, freeAllowances, baseSymbol, allowanceCost));
+ GetAllowanceCalculatedBaseOnPrimaryToken(tokenInfo, transactionFeeFreeAllowancesMap, baseSymbol,
+ allowanceCost));
}
private long GetAllowanceCalculatedBaseOnPrimaryToken(SymbolToPayTxSizeFee tokenInfo,
- MethodFeeFreeAllowances freeAllowances, string baseSymbol,
+ TransactionFeeFreeAllowancesMap transactionFeeFreeAllowancesMap, string baseSymbol,
long allowanceCost)
{
var availableAllowance =
- GetFreeFeeAllowanceAmount(freeAllowances,
+ GetFreeFeeAllowanceAmount(transactionFeeFreeAllowancesMap,
tokenInfo.TokenSymbol); //GetBalance(Context.Sender, tokenInfo.TokenSymbol);
if (tokenInfo.TokenSymbol == baseSymbol)
availableAllowance = availableAllowance.Sub(allowanceCost);
@@ -1083,29 +1389,25 @@ private long GetAllowanceCalculatedBaseOnPrimaryToken(SymbolToPayTxSizeFee token
}
private bool IsDelegationEnoughBaseOnPrimaryToken(SymbolToPayTxSizeFee tokenInfo, string baseSymbol, long cost,
- long txSizeFeeAmount, TransactionFeeDelegations delegations = null)
+ long txSizeFeeAmount, TransactionFeeDelegations delegations)
{
- if (delegations == null)
- {
- return true;
- }
-
- if (!delegations.Delegations.ContainsKey(tokenInfo.TokenSymbol)) return false;
-
txSizeFeeAmount = txSizeFeeAmount.Mul(tokenInfo.AddedTokenWeight)
.Div(tokenInfo.BaseTokenWeight);
+ return IsDelegationEnough(tokenInfo.TokenSymbol, baseSymbol, cost, txSizeFeeAmount, delegations);
+ }
- // If current symbol is base fee symbol, it should be taken into account too.
- if (tokenInfo.TokenSymbol != baseSymbol)
- {
- return delegations.Delegations[tokenInfo.TokenSymbol] >= txSizeFeeAmount;
- }
- else
+ private bool IsDelegationEnough(string txSymbol, string baseSymbol, long cost,
+ long txSizeFeeAmount, TransactionFeeDelegations delegations)
+ {
+ if (!delegations.IsUnlimitedDelegate)
{
- return delegations.Delegations[tokenInfo.TokenSymbol].Sub(cost) >= txSizeFeeAmount;
+ return delegations.Delegations.ContainsKey(txSymbol) && (baseSymbol == txSymbol
+ ? delegations.Delegations[txSymbol].Sub(cost)
+ : delegations.Delegations[txSymbol]) >= txSizeFeeAmount;
}
- }
+ return true;
+ }
private void AssertSymbolToPayTxFeeIsValid(string tokenSymbol, out long totalSupply)
{
diff --git a/contract/AElf.Contracts.MultiToken/TokenContract_Helper.cs b/contract/AElf.Contracts.MultiToken/TokenContract_Helper.cs
index d11e25b7de..ed210282d0 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContract_Helper.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContract_Helper.cs
@@ -1,3 +1,4 @@
+using System.Collections.Generic;
using System.Linq;
using System.Text;
using AElf.Contracts.Parliament;
@@ -15,7 +16,8 @@ public partial class TokenContract
{
private static bool IsValidSymbolChar(char character)
{
- return (character >= 'A' && character <= 'Z') || (character >= '0' && character <= '9') || character == TokenContractConstants.NFTSymbolSeparator;
+ return (character >= 'A' && character <= 'Z') || (character >= '0' && character <= '9') ||
+ character == TokenContractConstants.NFTSymbolSeparator;
}
private bool IsValidItemIdChar(char character)
@@ -49,6 +51,11 @@ private void AssertValidMemo(string memo)
"Invalid memo size.");
}
+ private void AssertValidInputAddress(Address input)
+ {
+ Assert(input != null && !input.Value.IsNullOrEmpty(), "Invalid input address.");
+ }
+
private void DoTransfer(Address from, Address to, string symbol, long amount, string memo = null)
{
Assert(from != to, "Can't do transfer to sender itself.");
@@ -76,41 +83,74 @@ private void ModifyBalance(Address address, string symbol, long addAmount)
State.Balances[address][symbol] = target;
}
- private void ModifyFreeFeeAllowanceAmount(MethodFeeFreeAllowances freeAllowances, string symbol, long addAmount)
+ private void ModifyFreeFeeAllowanceAmount(Address fromAddress,
+ TransactionFeeFreeAllowancesMap transactionFeeFreeAllowancesMap, string symbol,
+ long addAmount)
{
- var freeAllowance = GetFreeFeeAllowance(freeAllowances, symbol);
- if (freeAllowance != null)
+ var freeAllowanceAmount = GetFreeFeeAllowanceAmount(transactionFeeFreeAllowancesMap, symbol);
+ if (addAmount < 0 && freeAllowanceAmount < -addAmount)
+ {
+ Assert(false,
+ $"Insufficient amount of {symbol} for free fee allowance. Need amount: {-addAmount}; Current amount: {freeAllowanceAmount}");
+ }
+
+ // Sort symbols by expiration time
+ var symbolList = GetSymbolListSortedByExpirationTime(transactionFeeFreeAllowancesMap, fromAddress);
+
+ foreach (var s in symbolList)
{
- var before = freeAllowance.Amount;
- if (addAmount < 0 && before < -addAmount)
- Assert(false,
- $"Insufficient amount of {symbol} for free fee allowance. Need amount: {-addAmount}; Current amount: {before}");
+ if (addAmount >= 0) break;
+
+ if (!transactionFeeFreeAllowancesMap.Map[s].Map.ContainsKey(symbol)) continue;
+
+ var currentAllowance = transactionFeeFreeAllowancesMap.Map[s].Map[symbol].Amount;
+
+ if (currentAllowance == 0) continue;
+
+ addAmount += currentAllowance;
- var target = before.Add(addAmount);
- freeAllowance.Amount = target;
+ transactionFeeFreeAllowancesMap.Map[s].Map[symbol].Amount = addAmount >= 0 ? addAmount : 0;
}
}
- private long GetBalance(Address address, string symbol)
+ private List GetSymbolListSortedByExpirationTime(TransactionFeeFreeAllowancesMap transactionFeeFreeAllowancesMap,
+ Address fromAddress)
{
- return State.Balances[address][symbol];
+ return transactionFeeFreeAllowancesMap.Map.Keys.OrderBy(t =>
+ State.TransactionFeeFreeAllowancesConfigMap[t].RefreshSeconds - (Context.CurrentBlockTime -
+ State.TransactionFeeFreeAllowancesLastRefreshTimes[
+ fromAddress][t]).Seconds).ToList();
}
- private MethodFeeFreeAllowance GetFreeFeeAllowance(MethodFeeFreeAllowances freeAllowances, string symbol)
+
+ private long GetBalance(Address address, string symbol)
{
- return freeAllowances?.Value.FirstOrDefault(a => a.Symbol == symbol);
+ AssertValidInputAddress(address);
+ Assert(!string.IsNullOrWhiteSpace(symbol), "Invalid symbol.");
+
+ return State.Balances[address][symbol];
}
- private long GetFreeFeeAllowanceAmount(MethodFeeFreeAllowances freeAllowances, string symbol)
+ // private MethodFeeFreeAllowance GetFreeFeeAllowance(MethodFeeFreeAllowances freeAllowances, string symbol)
+ // {
+ // return freeAllowances?.Value.FirstOrDefault(a => a.Symbol == symbol);
+ // }
+
+ private long GetFreeFeeAllowanceAmount(TransactionFeeFreeAllowancesMap transactionFeeFreeAllowancesMap, string symbol)
{
- var existingAllowance = 0L;
- var freeAllowance = GetFreeFeeAllowance(freeAllowances, symbol);
- if (freeAllowance != null)
+ var allowance = 0L;
+ var map = transactionFeeFreeAllowancesMap.Map;
+
+ if (map == null) return allowance;
+
+ foreach (var freeAllowances in map.Values)
{
- existingAllowance = freeAllowance.Amount;
+ freeAllowances.Map.TryGetValue(symbol, out var freeAllowance);
+
+ allowance = allowance.Add(freeAllowance?.Amount ?? 0L);
}
- return existingAllowance;
+ return allowance;
}
private void AssertSystemContractOrLockWhiteListAddress(string symbol)
@@ -143,13 +183,13 @@ private void AssertCrossChainTransaction(Transaction originalTransaction, Addres
private void RegisterTokenInfo(TokenInfo tokenInfo)
{
- var existing = State.TokenInfos[tokenInfo.Symbol];
- Assert(existing == null || existing.Equals(new TokenInfo()), "Token already exists.");
+ CheckTokenExists(tokenInfo.Symbol);
Assert(!string.IsNullOrEmpty(tokenInfo.Symbol) && tokenInfo.Symbol.All(IsValidSymbolChar),
"Invalid symbol.");
Assert(!string.IsNullOrEmpty(tokenInfo.TokenName), "Token name can neither be null nor empty.");
Assert(tokenInfo.TotalSupply > 0, "Invalid total supply.");
Assert(tokenInfo.Issuer != null, "Invalid issuer address.");
+ Assert(tokenInfo.Owner != null, "Invalid owner address.");
State.TokenInfos[tokenInfo.Symbol] = tokenInfo;
}
@@ -195,10 +235,36 @@ private void AssertValidCreateInput(CreateInput input, SymbolType symbolType)
&& input.Symbol.Length > 0
&& input.Decimals >= 0
&& input.Decimals <= TokenContractConstants.MaxDecimals, "Invalid input.");
+
+ CheckSymbolLength(input.Symbol, symbolType);
+ if (symbolType == SymbolType.Nft) return;
+ CheckTokenAndCollectionExists(input.Symbol);
+ if (IsAddressInCreateWhiteList(Context.Sender)) CheckSymbolSeed(input.Symbol);
+ }
+
+ private void CheckTokenAndCollectionExists(string symbol)
+ {
+ var symbols = symbol.Split(TokenContractConstants.NFTSymbolSeparator);
+ var tokenSymbol = symbols.First();
+ CheckTokenExists(tokenSymbol);
+ var collectionSymbol = symbols.First() + TokenContractConstants.NFTSymbolSeparator +
+ TokenContractConstants.CollectionSymbolSuffix;
+ CheckTokenExists(collectionSymbol);
+ }
+
+ private void CheckTokenExists(string symbol)
+ {
+ var empty = new TokenInfo();
+ var existing = State.TokenInfos[symbol];
+ Assert(existing == null || existing.Equals(empty), "Token already exists.");
+ }
+
+ private void CheckSymbolLength(string symbol, SymbolType symbolType)
+ {
if (symbolType == SymbolType.Token)
- Assert(input.Symbol.Length <= TokenContractConstants.SymbolMaxLength, "Invalid token symbol length");
+ Assert(symbol.Length <= TokenContractConstants.SymbolMaxLength, "Invalid token symbol length");
if (symbolType == SymbolType.Nft || symbolType == SymbolType.NftCollection)
- Assert(input.Symbol.Length <= TokenContractConstants.NFTSymbolMaxLength, "Invalid NFT symbol length");
+ Assert(symbol.Length <= TokenContractConstants.NFTSymbolMaxLength, "Invalid NFT symbol length");
}
private void CheckCrossChainTokenContractRegistrationControllerAuthority()
@@ -265,4 +331,31 @@ private void FireExternalLogEvent(TokenInfo tokenInfo, TransferFromInput input)
NonIndexed = input.ToByteString()
});
}
+
+ private bool IsInLockWhiteList(Address address)
+ {
+ return address == GetElectionContractAddress() || address == GetVoteContractAddress();
+ }
+
+ private Address GetElectionContractAddress()
+ {
+ if (State.ElectionContractAddress.Value == null)
+ {
+ State.ElectionContractAddress.Value =
+ Context.GetContractAddressByName(SmartContractConstants.ElectionContractSystemName);
+ }
+
+ return State.ElectionContractAddress.Value;
+ }
+
+ private Address GetVoteContractAddress()
+ {
+ if (State.VoteContractAddress.Value == null)
+ {
+ State.VoteContractAddress.Value =
+ Context.GetContractAddressByName(SmartContractConstants.VoteContractSystemName);
+ }
+
+ return State.VoteContractAddress.Value;
+ }
}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.MultiToken/TokenContract_NFTHelper.cs b/contract/AElf.Contracts.MultiToken/TokenContract_NFTHelper.cs
index 3652a25f91..bddfb444bf 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContract_NFTHelper.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContract_NFTHelper.cs
@@ -10,7 +10,7 @@ private SymbolType GetCreateInputSymbolType(string symbol)
Assert(words[0].Length > 0 && words[0].All(IsValidCreateSymbolChar), "Invalid Symbol input");
if (words.Length == 1) return SymbolType.Token;
Assert(words.Length == 2 && words[1].Length > 0 && words[1].All(IsValidItemIdChar), "Invalid NFT Symbol input");
- return words[1] == "0" ? SymbolType.NftCollection : SymbolType.Nft;
+ return words[1] == TokenContractConstants.CollectionSymbolSuffix ? SymbolType.NftCollection : SymbolType.Nft;
}
private void AssertNFTCreateInput(CreateInput input)
diff --git a/contract/AElf.Contracts.MultiToken/TokenContract_NFT_Actions.cs b/contract/AElf.Contracts.MultiToken/TokenContract_NFT_Actions.cs
index 8d52fba4bd..1926727e68 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContract_NFT_Actions.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContract_NFT_Actions.cs
@@ -1,7 +1,5 @@
using System.Linq;
using AElf.CSharp.Core;
-using AElf.Sdk.CSharp;
-using AElf.Standards.ACS1;
using AElf.Types;
using Google.Protobuf.WellKnownTypes;
@@ -20,31 +18,49 @@ private Empty CreateNFTInfo(CreateInput input)
AssertNFTCreateInput(input);
var nftCollectionInfo = AssertNftCollectionExist(input.Symbol);
input.IssueChainId = input.IssueChainId == 0 ? nftCollectionInfo.IssueChainId : input.IssueChainId;
- Assert(input.IssueChainId == nftCollectionInfo.IssueChainId, "NFT create ChainId must be collection's issue chainId");
- Assert(Context.Sender == nftCollectionInfo.Issuer && nftCollectionInfo.Issuer == input.Issuer, "NFT issuer must be collection's issuer");
+ Assert(input.IssueChainId == nftCollectionInfo.IssueChainId,
+ "NFT create ChainId must be collection's issue chainId");
+
+ var owner = nftCollectionInfo.Owner ?? nftCollectionInfo.Issuer;
+ Assert(Context.Sender == owner && owner == input.Owner, "NFT owner must be collection's owner");
+
+ if (nftCollectionInfo.Symbol == TokenContractConstants.SeedCollectionSymbol)
+ {
+ Assert(input.ExternalInfo.Value.TryGetValue(TokenContractConstants.SeedOwnedSymbolExternalInfoKey,
+ out var ownedSymbol), "OwnedSymbol does not exist.");
+ Assert(input.ExternalInfo.Value.TryGetValue(TokenContractConstants.SeedExpireTimeExternalInfoKey,
+ out var expirationTime)
+ && long.TryParse(expirationTime, out var expirationTimeLong) &&
+ Context.CurrentBlockTime.Seconds <= expirationTimeLong, "Invalid ownedSymbol.");
+ var ownedSymbolType = GetCreateInputSymbolType(ownedSymbol);
+ Assert(ownedSymbolType != SymbolType.Nft, "Invalid OwnedSymbol.");
+ CheckSymbolLength(ownedSymbol, ownedSymbolType);
+ CheckTokenAndCollectionExists(ownedSymbol);
+ CheckSymbolSeed(ownedSymbol);
+ State.SymbolSeedMap[ownedSymbol] = input.Symbol;
+ }
+
return CreateToken(input, SymbolType.Nft);
}
- private void ChargeCreateFees()
+ private void CheckSymbolSeed(string ownedSymbol)
{
- if (Context.Sender == Context.Origin) return;
- if (IsAddressInCreateWhiteList(Context.Sender)) return;
+ var oldSymbolSeed = State.SymbolSeedMap[ownedSymbol];
- var fee = GetCreateMethodFee();
- Assert(fee != null, "not enough balance for create");
- DoTransferFrom(Context.Sender, Context.Self, Context.Self, fee.Symbol, fee.BasicFee, "");
-
- ModifyBalance(Context.Self, fee.Symbol, -fee.BasicFee);
- Context.Fire(new TransactionFeeCharged()
- {
- Symbol = fee.Symbol,
- Amount = fee.BasicFee,
- ChargingAddress = Context.Self
- });
+ Assert(oldSymbolSeed == null || !State.TokenInfos[oldSymbolSeed].ExternalInfo.Value
+ .TryGetValue(TokenContractConstants.SeedExpireTimeExternalInfoKey,
+ out var oldSymbolSeedExpireTime) ||
+ !long.TryParse(oldSymbolSeedExpireTime, out var symbolSeedExpireTime)
+ || Context.CurrentBlockTime.Seconds > symbolSeedExpireTime,
+ "OwnedSymbol has been created");
}
+
private void DoTransferFrom(Address from, Address to, Address spender, string symbol, long amount, string memo)
{
+ AssertValidInputAddress(from);
+ AssertValidInputAddress(to);
+
// First check allowance.
var allowance = State.Allowances[from][spender][symbol];
if (allowance < amount)
@@ -52,7 +68,8 @@ private void DoTransferFrom(Address from, Address to, Address spender, string sy
if (IsInWhiteList(new IsInWhiteListInput { Symbol = symbol, Address = spender }).Value)
{
DoTransfer(from, to, symbol, amount, memo);
- DealWithExternalInfoDuringTransfer(new TransferFromInput() { From = from, To = to, Symbol = symbol, Amount = amount, Memo = memo });
+ DealWithExternalInfoDuringTransfer(new TransferFromInput()
+ { From = from, To = to, Symbol = symbol, Amount = amount, Memo = memo });
return;
}
@@ -62,16 +79,11 @@ private void DoTransferFrom(Address from, Address to, Address spender, string sy
}
DoTransfer(from, to, symbol, amount, memo);
- DealWithExternalInfoDuringTransfer(new TransferFromInput() { From = from, To = to, Symbol = symbol, Amount = amount, Memo = memo });
+ DealWithExternalInfoDuringTransfer(new TransferFromInput()
+ { From = from, To = to, Symbol = symbol, Amount = amount, Memo = memo });
State.Allowances[from][spender][symbol] = allowance.Sub(amount);
}
- private MethodFee GetCreateMethodFee()
- {
- var fee = State.TransactionFees[nameof(Create)];
- if (fee == null || fee.Fees.Count <= 0) return new MethodFee { Symbol = Context.Variables.NativeSymbol, BasicFee = 10000_00000000 };
- return fee.Fees.FirstOrDefault(f => GetBalance(Context.Sender, f.Symbol) >= f.BasicFee);
- }
private string GetNftCollectionSymbol(string inputSymbol)
{
diff --git a/contract/AElf.Contracts.Profit/ProfitContract.cs b/contract/AElf.Contracts.Profit/ProfitContract.cs
index 5cd5514a71..c3c09b3aba 100644
--- a/contract/AElf.Contracts.Profit/ProfitContract.cs
+++ b/contract/AElf.Contracts.Profit/ProfitContract.cs
@@ -719,16 +719,6 @@ public override Empty ContributeProfits(ContributeProfitsInput input)
return new Empty();
}
-
- public override Empty IncreaseBackupSubsidyTotalShare(Hash schemeId)
- {
- Assert(!State.BackupSubsidyTotalShareIncreased.Value, "Already increased");
- State.BackupSubsidyTotalShareIncreased.Value = true;
- var scheme = State.SchemeInfos[schemeId];
- scheme.TotalShares = scheme.TotalShares.Add(1);
- State.SchemeInfos[schemeId] = scheme;
- return new Empty();
- }
public override Empty ResetManager(ResetManagerInput input)
{
diff --git a/contract/AElf.Contracts.Profit/ProfitContractState.cs b/contract/AElf.Contracts.Profit/ProfitContractState.cs
index 1648619f80..7a525e3ff6 100644
--- a/contract/AElf.Contracts.Profit/ProfitContractState.cs
+++ b/contract/AElf.Contracts.Profit/ProfitContractState.cs
@@ -17,6 +17,4 @@ public partial class ProfitContractState : ContractState
public MappedState TransactionFees { get; set; }
public SingletonState MethodFeeController { get; set; }
-
- public BoolState BackupSubsidyTotalShareIncreased { get; set; }
}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.Treasury/TreasuryContract.cs b/contract/AElf.Contracts.Treasury/TreasuryContract.cs
index 7f0c1c3ecc..6a75b5f448 100644
--- a/contract/AElf.Contracts.Treasury/TreasuryContract.cs
+++ b/contract/AElf.Contracts.Treasury/TreasuryContract.cs
@@ -606,7 +606,7 @@ public override Empty SetProfitsReceiver(SetProfitsReceiverInput input)
var pubkey = ByteString.CopyFrom(ByteArrayHelper.HexStringToByteArray(input.Pubkey));
var admin = State.ElectionContract.GetCandidateAdmin.Call(new StringValue {Value = input.Pubkey});
- Assert(Context.Origin == admin , "No permission.");
+ Assert(Context.Sender == admin , "No permission.");
var candidateList = State.ElectionContract.GetCandidates.Call(new Empty());
Assert(candidateList.Value.Contains(pubkey),"Pubkey is not a candidate.");
diff --git a/protobuf/aedpos_contract.proto b/protobuf/aedpos_contract.proto
index 73742d45fe..d06f5d5ccf 100644
--- a/protobuf/aedpos_contract.proto
+++ b/protobuf/aedpos_contract.proto
@@ -31,11 +31,11 @@ service AEDPoSContract {
}
// Update consensus information, create a new round.
- rpc NextRound (Round) returns (google.protobuf.Empty) {
+ rpc NextRound (NextRoundInput) returns (google.protobuf.Empty) {
}
// Update consensus information, create a new term.
- rpc NextTerm (Round) returns (google.protobuf.Empty) {
+ rpc NextTerm (NextTermInput) returns (google.protobuf.Empty) {
}
// Update consensus tiny block information.
@@ -216,6 +216,8 @@ message UpdateValueInput {
map miners_previous_in_values = 11;
// The irreversible block height that miner recorded.
int64 implied_irreversible_block_height = 12;
+ // The random number.
+ bytes random_number = 13;
}
message MinerList {
@@ -339,6 +341,8 @@ message AElfConsensusTriggerInformation {
map decrypted_pieces = 6;
// The revealed InValues.
map revealed_in_values = 7;
+ // The random number.
+ bytes random_number = 8;
}
message TermInfo {
@@ -360,6 +364,8 @@ message TinyBlockInput {
google.protobuf.Timestamp actual_mining_time = 2;
// Count of blocks currently produced
int64 produced_blocks = 3;
+ // The random number.
+ bytes random_number = 4;
}
message VoteMinersCountInput {
@@ -446,4 +452,56 @@ message MinerReplaced {
message RecordCandidateReplacementInput {
string old_pubkey = 1;
string new_pubkey = 2;
+}
+
+// For compatibility, it is the same as the Round with the addition of the random_number property.
+message NextRoundInput {
+ // The round number.
+ int64 round_number = 1;
+ // Current miner information, miner public key -> miner information.
+ map real_time_miners_information = 2;
+ // The round number on the main chain
+ int64 main_chain_miners_round_number = 3;
+ // The time from chain start to current round (seconds).
+ int64 blockchain_age = 4;
+ // The miner public key that produced the extra block in the previous round.
+ string extra_block_producer_of_previous_round = 5;
+ // The current term number.
+ int64 term_number = 6;
+ // The height of the confirmed irreversible block.
+ int64 confirmed_irreversible_block_height = 7;
+ // The round number of the confirmed irreversible block.
+ int64 confirmed_irreversible_block_round_number = 8;
+ // Is miner list different from the the miner list in the previous round.
+ bool is_miner_list_just_changed = 9;
+ // The round id, calculated by summing block producers’ expecting time (second).
+ int64 round_id_for_validation = 10;
+ // The random number.
+ bytes random_number = 11;
+}
+
+// For compatibility, it is the same as the Round with the addition of the random_number property.
+message NextTermInput {
+ // The round number.
+ int64 round_number = 1;
+ // Current miner information, miner public key -> miner information.
+ map real_time_miners_information = 2;
+ // The round number on the main chain
+ int64 main_chain_miners_round_number = 3;
+ // The time from chain start to current round (seconds).
+ int64 blockchain_age = 4;
+ // The miner public key that produced the extra block in the previous round.
+ string extra_block_producer_of_previous_round = 5;
+ // The current term number.
+ int64 term_number = 6;
+ // The height of the confirmed irreversible block.
+ int64 confirmed_irreversible_block_height = 7;
+ // The round number of the confirmed irreversible block.
+ int64 confirmed_irreversible_block_round_number = 8;
+ // Is miner list different from the the miner list in the previous round.
+ bool is_miner_list_just_changed = 9;
+ // The round id, calculated by summing block producers’ expecting time (second).
+ int64 round_id_for_validation = 10;
+ // The random number.
+ bytes random_number = 11;
}
\ No newline at end of file
diff --git a/protobuf/election_contract.proto b/protobuf/election_contract.proto
index 099a56590f..9720786297 100644
--- a/protobuf/election_contract.proto
+++ b/protobuf/election_contract.proto
@@ -341,6 +341,8 @@ message ElectorVote {
repeated ElectionVotingRecord withdrawn_votes_records = 6;
// Public key for voter.
bytes pubkey = 7;
+ // Address for voter
+ aelf.Address address = 8;
}
message CandidateVote {
diff --git a/protobuf/profit_contract.proto b/protobuf/profit_contract.proto
index b2fa18e712..1326da62ff 100644
--- a/protobuf/profit_contract.proto
+++ b/protobuf/profit_contract.proto
@@ -60,10 +60,6 @@ service ProfitContract {
rpc RemoveSubScheme (RemoveSubSchemeInput) returns (google.protobuf.Empty) {
}
- // Increase backup subsidy TotalShare
- rpc IncreaseBackupSubsidyTotalShare (aelf.Hash) returns (google.protobuf.Empty) {
- }
-
// Reset the manager of a scheme.
rpc ResetManager (ResetManagerInput) returns (google.protobuf.Empty) {
}
diff --git a/protobuf/test_mock_parliament_contract.proto b/protobuf/test_mock_parliament_contract.proto
new file mode 100644
index 0000000000..1024e5cd7d
--- /dev/null
+++ b/protobuf/test_mock_parliament_contract.proto
@@ -0,0 +1,24 @@
+syntax = "proto3";
+
+import "aelf/options.proto";
+import "aelf/core.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/wrappers.proto";
+
+option csharp_namespace = "AElf.Contracts.TestContract.MockParliament";
+
+service MockParliamentContract {
+ option (aelf.csharp_state) = "AElf.Contracts.TestContract.MockParliament.MockParliamentContractState";
+
+ rpc Initialize(InitializeInput) returns (google.protobuf.Empty) {
+ }
+
+ rpc GetDefaultOrganizationAddress (google.protobuf.Empty) returns (aelf.Address) {
+ option (aelf.is_view) = true;
+ }
+}
+
+message InitializeInput{
+ aelf.Address privileged_proposer = 1;
+ bool proposer_authority_required = 2;
+}
diff --git a/protobuf/test_virtual_address_contract.proto b/protobuf/test_virtual_address_contract.proto
new file mode 100644
index 0000000000..cdfb14fa05
--- /dev/null
+++ b/protobuf/test_virtual_address_contract.proto
@@ -0,0 +1,51 @@
+syntax = "proto3";
+
+import "aelf/options.proto";
+import "aelf/core.proto";
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/wrappers.proto";
+import "acs1.proto";
+
+option csharp_namespace = "AElf.Contracts.TestContract.VirtualAddress";
+
+service VirtualAddressContract {
+ option (aelf.csharp_state) = "AElf.Contracts.TestContract.VirtualAddress.State";
+ option (aelf.base) = "acs1.proto";
+
+ rpc VirtualAddressVote(VirtualAddressVoteInput) returns (google.protobuf.Empty);
+ rpc VirtualAddressWithdraw(aelf.Hash) returns (google.protobuf.Empty);
+ rpc VirtualAddressChangeVotingOption(VirtualAddressChangeVotingOptionInput) returns (google.protobuf.Empty);
+ rpc VirtualAddressClaimProfit(VirtualAddressClaimProfitInput) returns (google.protobuf.Empty);
+ rpc ForwardCall(ForwardCallInput) returns (google.protobuf.Empty);
+
+ rpc GetVirtualAddress(google.protobuf.Empty) returns (aelf.Address) {
+ option (aelf.is_view) = true;
+ }
+}
+
+message VirtualAddressVoteInput {
+ string pub_key = 1;
+ int64 amount = 2;
+ google.protobuf.Timestamp end_timestamp = 3;
+ // Used to generate vote id.
+ aelf.Hash token = 4;
+}
+
+message VirtualAddressChangeVotingOptionInput {
+ bool is_reset = 1;
+ aelf.Hash vote_id = 2;
+ string pub_key = 3;
+}
+
+message VirtualAddressClaimProfitInput {
+ aelf.Hash scheme_id = 1;
+ aelf.Address beneficiary = 2;
+}
+
+message ForwardCallInput {
+ aelf.Hash virtual_address = 1;
+ aelf.Address contract_address = 2;
+ string method_name = 3;
+ bytes args = 4;
+}
\ No newline at end of file
diff --git a/protobuf/test_vote_contract.proto b/protobuf/test_vote_contract.proto
new file mode 100644
index 0000000000..bc30611354
--- /dev/null
+++ b/protobuf/test_vote_contract.proto
@@ -0,0 +1,21 @@
+syntax = "proto3";
+
+import "aelf/core.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/wrappers.proto";
+import "acs1.proto";
+
+option csharp_namespace = "AElf.Contracts.TestContract.Vote";
+
+service VoteContract {
+ option (aelf.csharp_state) = "AElf.Contracts.TestContract.Vote.VoteContractState";
+ option (aelf.base) = "acs1.proto";
+
+ rpc AddOption (AddOptionInput) returns (google.protobuf.Empty) {
+ }
+}
+
+message AddOptionInput {
+ aelf.Hash voting_item_id = 1;
+ aelf.Hash option = 2;
+}
\ No newline at end of file
diff --git a/protobuf/token_contract.proto b/protobuf/token_contract.proto
index 6aea317b43..5082990a99 100644
--- a/protobuf/token_contract.proto
+++ b/protobuf/token_contract.proto
@@ -16,20 +16,20 @@ service TokenContract {
// Create a new token.
rpc Create (CreateInput) returns (google.protobuf.Empty) {
}
-
+
// Issuing some amount of tokens to an address is the action of increasing that addresses balance
// for the given token. The total amount of issued tokens must not exceed the total supply of the token
// and only the issuer (creator) of the token can issue tokens.
// Issuing tokens effectively increases the circulating supply.
rpc Issue (IssueInput) returns (google.protobuf.Empty) {
}
-
+
// Transferring tokens simply is the action of transferring a given amount of tokens from one address to another.
// The origin or source address is the signer of the transaction.
// The balance of the sender must be higher than the amount that is transferred.
rpc Transfer (TransferInput) returns (google.protobuf.Empty) {
}
-
+
// The TransferFrom action will transfer a specified amount of tokens from one address to another.
// For this operation to succeed the from address needs to have approved (see allowances) enough tokens
// to Sender of this transaction. If successful the amount will be removed from the allowance.
@@ -40,43 +40,39 @@ service TokenContract {
// enabling the Spender to call TransferFrom.
rpc Approve (ApproveInput) returns (google.protobuf.Empty) {
}
-
+
// This is the reverse operation for Approve, it will decrease the allowance.
rpc UnApprove (UnApproveInput) returns (google.protobuf.Empty) {
}
-
+
// This method can be used to lock tokens.
rpc Lock (LockInput) returns (google.protobuf.Empty) {
}
-
+
// This is the reverse operation of locking, it un-locks some previously locked tokens.
rpc Unlock (UnlockInput) returns (google.protobuf.Empty) {
}
-
+
// This action will burn the specified amount of tokens, removing them from the token’s Supply.
rpc Burn (BurnInput) returns (google.protobuf.Empty) {
}
-
- // Change the issuer of the specified token. Only the original issuer can change it.
- rpc ChangeTokenIssuer (ChangeTokenIssuerInput) returns (google.protobuf.Empty) {
- }
// Set the primary token of side chain.
rpc SetPrimaryTokenSymbol (SetPrimaryTokenSymbolInput) returns (google.protobuf.Empty) {
}
-
+
// This interface is used for cross-chain transfer.
rpc CrossChainTransfer (CrossChainTransferInput) returns (google.protobuf.Empty) {
}
-
+
// This method is used to receive cross-chain transfers.
rpc CrossChainReceiveToken (CrossChainReceiveTokenInput) returns (google.protobuf.Empty) {
}
-
+
// The side chain creates tokens.
- rpc CrossChainCreateToken(CrossChainCreateTokenInput) returns (google.protobuf.Empty) {
+ rpc CrossChainCreateToken(CrossChainCreateTokenInput) returns (google.protobuf.Empty) {
}
-
+
// When the side chain is started, the side chain is initialized with the parent chain information.
rpc InitializeFromParentChain (InitializeFromParentChainInput) returns (google.protobuf.Empty) {
}
@@ -84,13 +80,13 @@ service TokenContract {
// Handle the transaction fees charged by ChargeTransactionFees.
rpc ClaimTransactionFees (TotalTransactionFeesMap) returns (google.protobuf.Empty) {
}
-
+
// Used to collect transaction fees.
rpc ChargeTransactionFees (ChargeTransactionFeesInput) returns (ChargeTransactionFeesOutput) {
}
-
+
rpc ChargeUserContractTransactionFees(ChargeTransactionFeesInput) returns(ChargeTransactionFeesOutput){
-
+
}
// Check the token threshold.
@@ -100,108 +96,102 @@ service TokenContract {
// Initialize coefficients of every type of tokens supporting charging fee.
rpc InitialCoefficients (google.protobuf.Empty) returns (google.protobuf.Empty){
}
-
+
// Processing resource token received.
rpc DonateResourceToken (TotalResourceTokensMaps) returns (google.protobuf.Empty) {
}
-
+
// A transaction resource fee is charged to implement the ACS8 standards.
rpc ChargeResourceToken (ChargeResourceTokenInput) returns (google.protobuf.Empty) {
}
-
+
// Verify that the resource token are sufficient.
rpc CheckResourceToken (google.protobuf.Empty) returns (google.protobuf.Empty) {
}
-
+
// Set the list of tokens to pay transaction fees.
rpc SetSymbolsToPayTxSizeFee (SymbolListToPayTxSizeFee) returns (google.protobuf.Empty){
}
-
+
// Update the coefficient of the transaction fee calculation formula.
rpc UpdateCoefficientsForSender (UpdateCoefficientsInput) returns (google.protobuf.Empty) {
}
-
+
// Update the coefficient of the transaction fee calculation formula.
rpc UpdateCoefficientsForContract (UpdateCoefficientsInput) returns (google.protobuf.Empty) {
}
-
+
// This method is used to initialize the governance organization for some functions,
// including: the coefficient of the user transaction fee calculation formula,
// the coefficient of the contract developer resource fee calculation formula, and the side chain rental fee.
rpc InitializeAuthorizedController (google.protobuf.Empty) returns (google.protobuf.Empty){
}
- rpc ResetExternalInfo (ResetExternalInfoInput) returns (google.protobuf.Empty){
- }
-
rpc AddAddressToCreateTokenWhiteList (aelf.Address) returns (google.protobuf.Empty) {
}
rpc RemoveAddressFromCreateTokenWhiteList (aelf.Address) returns (google.protobuf.Empty) {
}
-
- rpc ConfigMethodFeeFreeAllowances (MethodFeeFreeAllowancesConfig) returns (google.protobuf.Empty) {
- }
-
+
rpc SetTransactionFeeDelegations (SetTransactionFeeDelegationsInput) returns (SetTransactionFeeDelegationsOutput){
}
-
+
rpc RemoveTransactionFeeDelegator (RemoveTransactionFeeDelegatorInput) returns (google.protobuf.Empty){
}
rpc RemoveTransactionFeeDelegatee (RemoveTransactionFeeDelegateeInput) returns (google.protobuf.Empty){
}
-
+
// Get all delegatees' address of delegator from input
rpc GetTransactionFeeDelegatees (GetTransactionFeeDelegateesInput) returns (GetTransactionFeeDelegateesOutput) {
-
+ option (aelf.is_view) = true;
}
// Query token information.
rpc GetTokenInfo (GetTokenInfoInput) returns (TokenInfo) {
option (aelf.is_view) = true;
}
-
+
// Query native token information.
rpc GetNativeTokenInfo (google.protobuf.Empty) returns (TokenInfo) {
option (aelf.is_view) = true;
}
-
+
// Query resource token information.
rpc GetResourceTokenInfo (google.protobuf.Empty) returns (TokenInfoList) {
option (aelf.is_view) = true;
}
-
+
// Query the balance at the specified address.
rpc GetBalance (GetBalanceInput) returns (GetBalanceOutput) {
option (aelf.is_view) = true;
}
-
+
// Query the account's allowance for other addresses
rpc GetAllowance (GetAllowanceInput) returns (GetAllowanceOutput) {
option (aelf.is_view) = true;
}
-
+
// Check whether the token is in the whitelist of an address,
// which can be called TransferFrom to transfer the token under the condition of not being credited.
rpc IsInWhiteList (IsInWhiteListInput) returns (google.protobuf.BoolValue) {
option (aelf.is_view) = true;
}
-
+
// Query the information for a lock.
rpc GetLockedAmount (GetLockedAmountInput) returns (GetLockedAmountOutput) {
option (aelf.is_view) = true;
}
-
+
// Query the address of receiving token in cross-chain transfer.
rpc GetCrossChainTransferTokenContractAddress (GetCrossChainTransferTokenContractAddressInput) returns (aelf.Address) {
option (aelf.is_view) = true;
}
-
+
// Query the name of the primary Token.
rpc GetPrimaryTokenSymbol (google.protobuf.Empty) returns (google.protobuf.StringValue) {
option (aelf.is_view) = true;
}
-
+
// Query the coefficient of the transaction fee calculation formula.
rpc GetCalculateFeeCoefficientsForContract (google.protobuf.Int32Value) returns (CalculateFeeCoefficients) {
option (aelf.is_view) = true;
@@ -211,17 +201,17 @@ service TokenContract {
rpc GetCalculateFeeCoefficientsForSender (google.protobuf.Empty) returns (CalculateFeeCoefficients) {
option (aelf.is_view) = true;
}
-
+
// Query tokens that can pay transaction fees.
rpc GetSymbolsToPayTxSizeFee (google.protobuf.Empty) returns (SymbolListToPayTxSizeFee){
option (aelf.is_view) = true;
}
-
+
// Query the hash of the last input of ClaimTransactionFees.
rpc GetLatestTotalTransactionFeesMapHash (google.protobuf.Empty) returns (aelf.Hash){
option (aelf.is_view) = true;
}
-
+
// Query the hash of the last input of DonateResourceToken.
rpc GetLatestTotalResourceTokensMapsHash (google.protobuf.Empty) returns (aelf.Hash){
option (aelf.is_view) = true;
@@ -232,15 +222,9 @@ service TokenContract {
rpc GetReservedExternalInfoKeyList (google.protobuf.Empty) returns (StringList) {
option (aelf.is_view) = true;
}
- rpc GetMethodFeeFreeAllowances (aelf.Address) returns (MethodFeeFreeAllowances) {
- option (aelf.is_view) = true;
- }
- rpc GetMethodFeeFreeAllowancesConfig (google.protobuf.Empty) returns (MethodFeeFreeAllowancesConfig) {
- option (aelf.is_view) = true;
- }
-
+
rpc GetTransactionFeeDelegationsOfADelegatee(GetTransactionFeeDelegationsOfADelegateeInput) returns(TransactionFeeDelegations){
- option (aelf.is_view) = true;
+ option (aelf.is_view) = true;
}
}
@@ -255,7 +239,7 @@ message TokenInfo {
int64 total_supply = 4;
// The precision of the token.
int32 decimals = 5;
- // The address that created the token.
+ // The address that has permission to issue the token.
aelf.Address issuer = 6;
// A flag indicating if this token is burnable.
bool is_burnable = 7;
@@ -265,6 +249,8 @@ message TokenInfo {
int64 issued = 9;
// The external information of the token.
ExternalInfo external_info = 10;
+ // The address that owns the token.
+ aelf.Address owner = 11;
}
message ExternalInfo {
@@ -280,7 +266,7 @@ message CreateInput {
int64 total_supply = 3;
// The precision of the token
int32 decimals = 4;
- // The address that created the token.
+ // The address that has permission to issue the token.
aelf.Address issuer = 5;
// A flag indicating if this token is burnable.
bool is_burnable = 6;
@@ -290,6 +276,8 @@ message CreateInput {
int32 issue_chain_id = 8;
// The external information of the token.
ExternalInfo external_info = 9;
+ // The address that owns the token.
+ aelf.Address owner = 10;
}
message SetPrimaryTokenSymbolInput {
@@ -321,7 +309,7 @@ message TransferInput {
message LockInput {
// The one want to lock his token.
- aelf.Address address = 1;
+ aelf.Address address = 1;
// Id of the lock.
aelf.Hash lock_id = 2;
// The symbol of the token to lock.
@@ -661,33 +649,20 @@ message StringList {
repeated string value = 1;
}
-message MethodFeeFreeAllowancesConfig {
- MethodFeeFreeAllowances free_allowances = 1;
- int64 refresh_seconds = 2;
- int64 threshold = 3;
-}
-
-message MethodFeeFreeAllowances {
- repeated MethodFeeFreeAllowance value = 1;
-}
-
-message MethodFeeFreeAllowance {
- string symbol = 1;
- int64 amount = 2;
-}
-
message TransactionFeeDelegations{
// delegation, symbols and its' amount
map delegations = 1;
// height when added
int64 block_height = 2;
+ //Whether to pay transaction fee continuously
+ bool isUnlimitedDelegate = 3;
}
message TransactionFeeDelegatees{
map delegatees = 1;
}
-message SetTransactionFeeDelegationsInput {
+message SetTransactionFeeDelegationsInput {
// the delegator address
aelf.Address delegator_address = 1;
// delegation, symbols and its' amount
@@ -790,6 +765,10 @@ message RentalCharged {
string symbol = 1;
// The amount of rental fee charged.
int64 amount = 2;
+ // The payer of rental fee.
+ aelf.Address payer = 3;
+ // The receiver of rental fee.
+ aelf.Address receiver = 4;
}
message RentalAccountBalanceInsufficient {
@@ -810,7 +789,7 @@ message TokenCreated {
int64 total_supply = 3;
// The precision of the token.
int32 decimals = 4;
- // The address that created the token.
+ // The address that has permission to issue the token.
aelf.Address issuer = 5;
// A flag indicating if this token is burnable.
bool is_burnable = 6;
@@ -818,6 +797,8 @@ message TokenCreated {
int32 issue_chain_id = 7;
// The external information of the token.
ExternalInfo external_info = 8;
+ // The address that owns the token.
+ aelf.Address owner = 9;
}
message Issued {
diff --git a/protobuf/token_contract_impl.proto b/protobuf/token_contract_impl.proto
index 939c15344f..97acd5b439 100644
--- a/protobuf/token_contract_impl.proto
+++ b/protobuf/token_contract_impl.proto
@@ -77,6 +77,24 @@ service TokenContractImpl {
rpc ChangeDeveloperController (AuthorityInfo) returns (google.protobuf.Empty) {
}
+ rpc ConfigTransactionFeeFreeAllowances (ConfigTransactionFeeFreeAllowancesInput) returns (google.protobuf.Empty) {
+ }
+
+ rpc RemoveTransactionFeeFreeAllowancesConfig (RemoveTransactionFeeFreeAllowancesConfigInput) returns (google.protobuf.Empty) {
+ }
+
+ // Delegatee sets the delegation and related information of the delegator based on a transaction.
+ rpc SetTransactionFeeDelegateInfos (SetTransactionFeeDelegateInfosInput) returns (google.protobuf.Empty){
+ }
+
+ // Delegatee remove delegator info based on a transaction.
+ rpc RemoveTransactionFeeDelegatorInfos (RemoveTransactionFeeDelegatorInfosInput) returns (google.protobuf.Empty){
+ }
+
+ // Delegator remove delegatee info based on a transaction.
+ rpc RemoveTransactionFeeDelegateeInfos (RemoveTransactionFeeDelegateeInfosInput) returns (google.protobuf.Empty){
+ }
+
// Get the address of fee receiver.
rpc GetFeeReceiver (google.protobuf.Empty) returns (aelf.Address){
option (aelf.is_view) = true;
@@ -128,6 +146,23 @@ service TokenContractImpl {
rpc GetOwningRentalUnitValue (google.protobuf.Empty) returns (OwningRentalUnitValue) {
option (aelf.is_view) = true;
}
+
+ // Query
+ rpc GetTransactionFeeFreeAllowances (aelf.Address) returns (TransactionFeeFreeAllowancesMap) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetTransactionFeeFreeAllowancesConfig (google.protobuf.Empty) returns (GetTransactionFeeFreeAllowancesConfigOutput) {
+ option (aelf.is_view) = true;
+ }
+
+ // Get delegatee info list according to the delegator and transaction.
+ rpc GetTransactionFeeDelegateeList (GetTransactionFeeDelegateeListInput) returns (GetTransactionFeeDelegateeListOutput) {
+ option (aelf.is_view) = true;
+ }
+ // Get delegation according to the delegator,transaction and delegatee.
+ rpc GetTransactionFeeDelegateInfo(GetTransactionFeeDelegateInfoInput) returns (token.TransactionFeeDelegations){
+ option (aelf.is_view) = true;
+ }
}
message AdvanceResourceTokenInput {
@@ -170,7 +205,7 @@ message ValidateTokenInfoExistsInput{
int64 total_supply = 3;
// The precision of the token.
int32 decimals = 4;
- // The address that created the token.
+ // The address that has permission to issue the token.
aelf.Address issuer = 5;
// A flag indicating if this token is burnable.
bool is_burnable = 6;
@@ -178,6 +213,8 @@ message ValidateTokenInfoExistsInput{
int32 issue_chain_id = 7;
// The external information of the token.
map external_info = 8;
+ // The address that owns the token.
+ aelf.Address owner = 9;
}
message UpdateRentalInput {
@@ -244,3 +281,138 @@ enum SymbolType {
NFT = 1;
NFT_COLLECTION = 2;
}
+
+message MethodFeeFreeAllowancesConfig {
+ MethodFeeFreeAllowances free_allowances = 1;
+ int64 refresh_seconds = 2;
+ int64 threshold = 3;
+}
+
+message MethodFeeFreeAllowances{
+ repeated MethodFeeFreeAllowance value = 1;
+}
+
+message MethodFeeFreeAllowance {
+ string symbol = 1;
+ int64 amount = 2;
+}
+
+message TransactionFeeFreeAllowances{
+ repeated TransactionFeeFreeAllowance value = 1;
+}
+
+message TransactionFeeFreeAllowance {
+ string symbol = 1;
+ int64 amount = 2;
+}
+
+message TransactionFeeFreeAllowancesSymbolList {
+ repeated string symbols = 1;
+}
+
+message ConfigTransactionFeeFreeAllowancesInput {
+ repeated ConfigTransactionFeeFreeAllowance value = 1;
+}
+
+message ConfigTransactionFeeFreeAllowance {
+ string symbol = 1;
+ TransactionFeeFreeAllowances transaction_fee_free_allowances = 2;
+ int64 refresh_seconds = 3;
+ int64 threshold = 4;
+}
+
+message RemoveTransactionFeeFreeAllowancesConfigInput {
+ repeated string symbols = 1;
+}
+
+message GetTransactionFeeFreeAllowancesConfigOutput {
+ repeated TransactionFeeFreeAllowanceConfig value = 1;
+}
+
+message TransactionFeeFreeAllowanceConfig {
+ string symbol = 1;
+ TransactionFeeFreeAllowanceMap free_allowances = 2;
+ int64 refresh_seconds = 3;
+ int64 threshold = 4;
+}
+
+message TransactionFeeFreeAllowanceMap {
+ map map = 1;
+}
+
+message TransactionFeeFreeAllowancesMap {
+ map map = 1;
+}
+
+message SetTransactionFeeDelegateInfosInput{
+ // the delegator address
+ aelf.Address delegator_address = 1;
+ //delegate info list (support batch)
+ repeated DelegateInfo delegate_info_list = 2;
+}
+message DelegateInfo{
+ //symbol->amount
+ map delegations = 1;
+ aelf.Address contract_address = 2;
+ string method_name = 3;
+ //Whether to pay transaction fee continuously
+ bool isUnlimitedDelegate = 4;
+}
+
+message RemoveTransactionFeeDelegatorInfosInput{
+ // the delegator address
+ aelf.Address delegator_address = 1;
+ // delegate transaction info (support batch)
+ repeated DelegateTransaction delegate_transaction_list = 2;
+}
+message DelegateTransaction{
+ aelf.Address contract_address = 1;
+ string method_name = 2;
+}
+message DelegateTransactionList{
+ repeated DelegateTransaction value = 1;
+}
+
+message RemoveTransactionFeeDelegateeInfosInput {
+ // the delegatee address
+ aelf.Address delegatee_address = 1;
+ // delegate transaction info (support batch)
+ repeated DelegateTransaction delegate_transaction_list = 2;
+}
+
+message GetTransactionFeeDelegateInfoInput {
+ aelf.Address delegator_address = 1;
+ aelf.Address delegatee_address = 2;
+ aelf.Address contract_address = 3;
+ string method_name = 4;
+}
+message GetTransactionFeeDelegateeListInput {
+ aelf.Address delegator_address = 1;
+ aelf.Address contract_address = 2;
+ string method_name = 3;
+}
+message GetTransactionFeeDelegateeListOutput {
+ repeated aelf.Address delegatee_addresses = 1;
+}
+message TransactionFeeDelegateInfoAdded {
+ option (aelf.is_event) = true;
+ aelf.Address delegator = 1;
+ aelf.Address delegatee = 2;
+ aelf.Address caller = 3;
+ DelegateTransactionList delegate_transaction_list = 4;
+}
+message TransactionFeeDelegateInfoUpdated {
+ option (aelf.is_event) = true;
+ aelf.Address delegator = 1 ;
+ aelf.Address delegatee = 2 ;
+ aelf.Address caller = 3 ;
+ DelegateTransactionList delegate_transaction_list = 4;
+}
+
+message TransactionFeeDelegateInfoCancelled {
+ option (aelf.is_event) = true;
+ aelf.Address delegator = 1 ;
+ aelf.Address delegatee = 2 ;
+ aelf.Address caller = 3 ;
+ DelegateTransactionList delegate_transaction_list = 4;
+}
diff --git a/protobuf/transaction_fee.proto b/protobuf/transaction_fee.proto
index 47f9f4af24..57f7c16d04 100644
--- a/protobuf/transaction_fee.proto
+++ b/protobuf/transaction_fee.proto
@@ -43,4 +43,19 @@ message ResourceTokenOwned {
string symbol = 1;
int64 amount = 2;
aelf.Address contract_address = 3;
+}
+
+message TransactionFeeClaimed {
+ option (aelf.is_event) = true;
+ string symbol = 1;
+ int64 amount = 2;
+ aelf.Address receiver = 3;
+}
+
+message ResourceTokenClaimed {
+ option (aelf.is_event) = true;
+ string symbol = 1;
+ int64 amount = 2;
+ aelf.Address payer = 3;
+ aelf.Address receiver = 4;
}
\ No newline at end of file
diff --git a/src/AElf.ContractTestBase/AElf.ContractTestBase.csproj b/src/AElf.ContractTestBase/AElf.ContractTestBase.csproj
index 40a637defe..cb38e8bf85 100644
--- a/src/AElf.ContractTestBase/AElf.ContractTestBase.csproj
+++ b/src/AElf.ContractTestBase/AElf.ContractTestBase.csproj
@@ -18,6 +18,11 @@
+
+ false
+ Contract
+ PreserveNewest
+
@@ -39,6 +44,15 @@
Protobuf\Proto\basic_contract_zero.proto
+
+ Protobuf\Proto\parliament_contract.proto
+
+
+ Protobuf\Proto\parliament_contract_impl.proto
+
+
+ Protobuf\Proto\acs3.proto
+
diff --git a/src/AElf.ContractTestBase/ContractTestKit/ContractTestBase.cs b/src/AElf.ContractTestBase/ContractTestKit/ContractTestBase.cs
index 765afaa90e..f9c435327f 100644
--- a/src/AElf.ContractTestBase/ContractTestKit/ContractTestBase.cs
+++ b/src/AElf.ContractTestBase/ContractTestKit/ContractTestBase.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using AElf.Contracts.Parliament;
using AElf.CrossChain;
using AElf.Cryptography.ECDSA;
using AElf.CSharp.Core;
@@ -16,7 +17,9 @@
using AElf.Kernel.SmartContract.Application;
using AElf.Kernel.Token;
using AElf.Standards.ACS0;
+using AElf.Standards.ACS3;
using AElf.Types;
+using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
@@ -45,6 +48,9 @@ public ContractTestBase()
protected IReadOnlyList Accounts => SampleAccount.Accounts;
protected int InitialCoreDataCenterCount => 5;
+
+ protected List InitialCoreDataCenterKeyPairs =>
+ Accounts.Take(InitialCoreDataCenterCount).Select(a => a.KeyPair).ToList();
protected Dictionary SystemContractAddresses { get; } = new();
@@ -155,4 +161,34 @@ private IAbpApplication CreateApplication(ChainInitializationDto dto) where T
application.Initialize();
return application;
}
+
+ protected async Task SubmitAndApproveProposalOfDefaultParliament(Address contractAddress, string methodName,
+ IMessage message)
+ {
+ var parliamentContractStub = GetTester(ParliamentContractAddress, DefaultAccount.KeyPair);
+ var defaultParliamentAddress =
+ await parliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
+
+ var proposal = new CreateProposalInput
+ {
+ OrganizationAddress = defaultParliamentAddress,
+ ContractMethodName = methodName,
+ ExpiredTime = TimestampHelper.GetUtcNow().AddHours(1),
+ Params = message.ToByteString(),
+ ToAddress = contractAddress
+ };
+ var createResult = await parliamentContractStub.CreateProposal.SendAsync(proposal);
+ var proposalId = createResult.Output;
+ await ApproveWithMinersAsync(proposalId);
+ await parliamentContractStub.Release.SendAsync(proposalId);
+ }
+
+ private async Task ApproveWithMinersAsync(Hash proposalId)
+ {
+ foreach (var bp in InitialCoreDataCenterKeyPairs)
+ {
+ var tester = GetTester(ParliamentContractAddress, bp);
+ await tester.Approve.SendAsync(proposalId);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/AElf.ContractTestKit.AEDPoSExtension/AElf.ContractTestKit.AEDPoSExtension.csproj b/src/AElf.ContractTestKit.AEDPoSExtension/AElf.ContractTestKit.AEDPoSExtension.csproj
index 515b666c92..8230cdb5e4 100644
--- a/src/AElf.ContractTestKit.AEDPoSExtension/AElf.ContractTestKit.AEDPoSExtension.csproj
+++ b/src/AElf.ContractTestKit.AEDPoSExtension/AElf.ContractTestKit.AEDPoSExtension.csproj
@@ -10,9 +10,9 @@
-
-
-
+
+
+
@@ -49,10 +49,10 @@
-
-
+
+
-
+
\ No newline at end of file
diff --git a/src/AElf.ContractTestKit.AEDPoSExtension/BlockMiningService.cs b/src/AElf.ContractTestKit.AEDPoSExtension/BlockMiningService.cs
index 87cc138f45..85e43156e9 100644
--- a/src/AElf.ContractTestKit.AEDPoSExtension/BlockMiningService.cs
+++ b/src/AElf.ContractTestKit.AEDPoSExtension/BlockMiningService.cs
@@ -7,6 +7,8 @@
using System.Threading.Tasks;
using AElf.ContractDeployer;
using AElf.Contracts.Consensus.AEDPoS;
+using AElf.Cryptography;
+using AElf.Cryptography.ECDSA;
using AElf.CSharp.Core.Extension;
using AElf.Kernel;
using AElf.Kernel.Blockchain.Application;
@@ -34,6 +36,7 @@ public class BlockMiningService : IBlockMiningService
private readonly ISmartContractAddressService _smartContractAddressService;
private readonly ITestDataProvider _testDataProvider;
private readonly ITransactionResultService _transactionResultService;
+ private readonly IBlockchainService _blockchainService;
private Address _consensusContractAddress;
@@ -52,6 +55,7 @@ public BlockMiningService(IServiceProvider serviceProvider)
_testDataProvider = serviceProvider.GetRequiredService();
_transactionResultService = serviceProvider.GetRequiredService();
_chainTypeProvider = serviceProvider.GetRequiredService();
+ _blockchainService = serviceProvider.GetRequiredService();
}
///
@@ -130,7 +134,8 @@ public async Task MineBlockAsync(List transactions = null, bool wit
throw new InitializationFailedException("Can't find current round information.");
}
- var triggerInformation = await GetConsensusTriggerInfoAsync(contractStub, pubkey);
+ var randomNumber = await GenerateRandomProofAsync();
+ var triggerInformation = await GetConsensusTriggerInfoAsync(contractStub, pubkey, ByteString.CopyFrom(randomNumber));
var consensusTransaction = await contractStub.GenerateConsensusTransactions.CallAsync(new BytesValue
{
Value = triggerInformation.ToByteString()
@@ -157,6 +162,17 @@ public async Task MineBlockAsync(List transactions = null, bool wit
_isSkipped = false;
}
+ private async Task GenerateRandomProofAsync()
+ {
+ var blockHeight = (await _blockchainService.GetChainAsync()).BestChainHeight;
+ var previousRandomHash =
+ blockHeight <= 1
+ ? Hash.Empty
+ : await _contractStubs.First().GetRandomHash.CallAsync(new Int64Value
+ { Value = blockHeight });
+ return CryptoHelper.ECVrfProve((ECKeyPair)_testDataProvider.GetKeyPair(), previousRandomHash.ToByteArray());
+ }
+
public async Task MineBlockToNextRoundAsync()
{
var consensusStub = _contractTesterFactory.Create(
@@ -294,16 +310,16 @@ await contractStub.UpdateValue.SendWithExceptionAsync(
break;
case nameof(AEDPoSContractImplContainer.AEDPoSContractImplStub.NextRound):
if (withException)
- await contractStub.NextRound.SendWithExceptionAsync(Round.Parser.ParseFrom(transaction.Params));
+ await contractStub.NextRound.SendWithExceptionAsync(NextRoundInput.Parser.ParseFrom(transaction.Params));
else
- await contractStub.NextRound.SendAsync(Round.Parser.ParseFrom(transaction.Params));
+ await contractStub.NextRound.SendAsync(NextRoundInput.Parser.ParseFrom(transaction.Params));
break;
case nameof(AEDPoSContractImplContainer.AEDPoSContractImplStub.NextTerm):
if (withException)
- await contractStub.NextTerm.SendWithExceptionAsync(Round.Parser.ParseFrom(transaction.Params));
+ await contractStub.NextTerm.SendWithExceptionAsync(NextTermInput.Parser.ParseFrom(transaction.Params));
else
- await contractStub.NextTerm.SendAsync(Round.Parser.ParseFrom(transaction.Params));
+ await contractStub.NextTerm.SendAsync(NextTermInput.Parser.ParseFrom(transaction.Params));
break;
}
@@ -378,7 +394,7 @@ await contractStub.UpdateValue.SendWithExceptionAsync(
}
private async Task GetConsensusTriggerInfoAsync(
- AEDPoSContractImplContainer.AEDPoSContractImplStub contractStub, BytesValue pubkey)
+ AEDPoSContractImplContainer.AEDPoSContractImplStub contractStub, BytesValue pubkey, ByteString randomNumber)
{
var command = await contractStub.GetConsensusCommand.CallAsync(pubkey);
var hint = AElfConsensusHint.Parser.ParseFrom(command.Hint);
@@ -388,7 +404,8 @@ private async Task GetConsensusTriggerInfoAsync
// It doesn't matter for testing.
InValue = HashHelper.ComputeFrom($"InValueOf{pubkey}"),
PreviousInValue = HashHelper.ComputeFrom($"InValueOf{pubkey}"),
- Pubkey = pubkey.Value
+ Pubkey = pubkey.Value,
+ RandomNumber = randomNumber
};
var consensusExtraData = await contractStub.GetConsensusExtraData.CallAsync(new BytesValue
diff --git a/src/AElf.ContractTestKit/ContractTestBase.cs b/src/AElf.ContractTestKit/ContractTestBase.cs
index 21c26e6aff..170ac0a9b9 100644
--- a/src/AElf.ContractTestKit/ContractTestBase.cs
+++ b/src/AElf.ContractTestKit/ContractTestBase.cs
@@ -1,18 +1,24 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
using AElf.ContractDeployer;
using AElf.Contracts.Genesis;
+using AElf.Contracts.Parliament;
using AElf.Cryptography.ECDSA;
using AElf.CSharp.Core;
+using AElf.CSharp.Core.Extension;
using AElf.Kernel;
using AElf.Kernel.Blockchain.Application;
using AElf.Kernel.Blockchain.Domain;
using AElf.Kernel.Infrastructure;
+using AElf.Kernel.Proposal;
using AElf.Kernel.SmartContract.Application;
using AElf.Standards.ACS0;
+using AElf.Standards.ACS3;
using AElf.Types;
using Google.Protobuf;
+using Google.Protobuf.WellKnownTypes;
using MartinCostello.Logging.XUnit;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
diff --git a/src/AElf.Cryptography/AElf.Cryptography.csproj b/src/AElf.Cryptography/AElf.Cryptography.csproj
index 0ac287552c..65f0ded71e 100644
--- a/src/AElf.Cryptography/AElf.Cryptography.csproj
+++ b/src/AElf.Cryptography/AElf.Cryptography.csproj
@@ -1,5 +1,5 @@
-
+
net6.0
AElf.Cryptography
@@ -7,12 +7,12 @@
Cryptographic primitives used in AElf.
-
-
-
-
+
+
+
+
-
+
diff --git a/src/AElf.Cryptography/Core/Exceptions.cs b/src/AElf.Cryptography/Core/Exceptions.cs
new file mode 100644
index 0000000000..99bf00dd80
--- /dev/null
+++ b/src/AElf.Cryptography/Core/Exceptions.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace AElf.Cryptography.Core;
+
+public class InvalidSerializedPublicKeyException : Exception
+{
+}
+public class FailedToSerializePointException : Exception
+{
+}
+public class FailedToCreatePointFromScalarException : Exception
+{
+}
+public class FailedToNegatePublicKeyException : Exception
+{
+}
+
+public class FailedToCombinePublicKeysException : Exception
+{
+}
+
+public class FailedToMultiplyScalarException : Exception
+{
+}
+
+public class FailedToGetNonceException : Exception
+{
+}
\ No newline at end of file
diff --git a/src/AElf.Cryptography/Core/Helpers.cs b/src/AElf.Cryptography/Core/Helpers.cs
new file mode 100644
index 0000000000..0faa2f68c7
--- /dev/null
+++ b/src/AElf.Cryptography/Core/Helpers.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Linq;
+using Org.BouncyCastle.Math;
+
+namespace AElf.Cryptography.Core;
+
+public static class Helpers
+{
+ public static byte[] AddLeadingZeros(byte[] data, int requiredLength)
+ {
+ var zeroBytesLength = requiredLength - data.Length;
+ if (zeroBytesLength <= 0) return data;
+ var output = new byte[requiredLength];
+ Buffer.BlockCopy(data, 0, output, zeroBytesLength, data.Length);
+ for (int i = zeroBytesLength - 1; i >= 0; i--)
+ {
+ output[i] = 0x0;
+ }
+
+ return output;
+ }
+
+
+ public static byte[] Int2Bytes(BigInteger v, int rolen)
+ {
+ var result = v.ToByteArray();
+ if (result.Length < rolen)
+ {
+ return AddLeadingZeros(result, rolen);
+ }
+
+ if (result.Length > rolen)
+ {
+ var skipLength = result.Length - rolen;
+ return result.Skip(skipLength).ToArray();
+ }
+
+ return result;
+ }
+
+ public static BigInteger Bits2Int(byte[] inputBytes, int qlen)
+ {
+ var output = new BigInteger(1, inputBytes);
+ if (inputBytes.Length * 8 > qlen)
+ {
+ return output.ShiftRight(inputBytes.Length * 8 - qlen);
+ }
+
+ return output;
+ }
+
+ public static byte[] Bits2Bytes(byte[] input, BigInteger q, int rolen)
+ {
+ var z1 = Bits2Int(input, q.BitLength);
+ var z2 = z1.Subtract(q);
+ if (z2.SignValue == -1)
+ {
+ return Int2Bytes(z1, rolen);
+ }
+
+ return Int2Bytes(z2, rolen);
+ }
+}
\ No newline at end of file
diff --git a/src/AElf.Cryptography/Core/IECCurve.cs b/src/AElf.Cryptography/Core/IECCurve.cs
new file mode 100644
index 0000000000..5fef5efed6
--- /dev/null
+++ b/src/AElf.Cryptography/Core/IECCurve.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace AElf.Cryptography.Core;
+
+public interface IECCurve : IDisposable
+{
+ IECPoint MultiplyScalar(IECPoint point, IECScalar scalar);
+ IECPoint GetPoint(IECScalar scalar);
+ byte[] SerializePoint(IECPoint point, bool compressed);
+ IECPoint Add(IECPoint point1, IECPoint point2);
+ IECPoint Sub(IECPoint point1, IECPoint point2);
+ IECPoint DeserializePoint(byte[] input);
+ IECScalar DeserializeScalar(byte[] input);
+ byte[] GetNonce(IECScalar privateKey, byte[] hash);
+}
\ No newline at end of file
diff --git a/src/AElf.Cryptography/Core/IECPoint.cs b/src/AElf.Cryptography/Core/IECPoint.cs
new file mode 100644
index 0000000000..5fc6b82132
--- /dev/null
+++ b/src/AElf.Cryptography/Core/IECPoint.cs
@@ -0,0 +1,6 @@
+namespace AElf.Cryptography.Core;
+
+public interface IECPoint
+{
+ byte[] Representation { get; }
+}
\ No newline at end of file
diff --git a/src/AElf.Cryptography/Core/IECScalar.cs b/src/AElf.Cryptography/Core/IECScalar.cs
new file mode 100644
index 0000000000..071d09f11a
--- /dev/null
+++ b/src/AElf.Cryptography/Core/IECScalar.cs
@@ -0,0 +1,6 @@
+namespace AElf.Cryptography.Core;
+
+public interface IECScalar
+{
+ byte[] Representation { get; }
+}
\ No newline at end of file
diff --git a/src/AElf.Cryptography/Core/Secp256k1Curve.cs b/src/AElf.Cryptography/Core/Secp256k1Curve.cs
new file mode 100644
index 0000000000..6f59c49e5e
--- /dev/null
+++ b/src/AElf.Cryptography/Core/Secp256k1Curve.cs
@@ -0,0 +1,121 @@
+using System;
+using System.Linq;
+using Secp256k1Net;
+
+namespace AElf.Cryptography.Core;
+
+public sealed class Secp256k1Curve : IECCurve
+{
+ private Secp256k1 _inner;
+
+ public Secp256k1Curve()
+ {
+ _inner = new Secp256k1();
+ }
+
+ public IECPoint MultiplyScalar(IECPoint point, IECScalar scalar)
+ {
+ var output = point.Representation;
+ if (!_inner.PublicKeyMultiply(output, scalar.Representation))
+ {
+ throw new FailedToMultiplyScalarException();
+ }
+
+ return Secp256k1Point.FromNative(output);
+ }
+
+ public IECPoint GetPoint(IECScalar scalar)
+ {
+ var pkBytes = new byte[Secp256k1.PUBKEY_LENGTH];
+ if (!_inner.PublicKeyCreate(pkBytes, scalar.Representation))
+ {
+ throw new FailedToCreatePointFromScalarException();
+ }
+
+ return Secp256k1Point.FromNative(pkBytes);
+ }
+
+ public byte[] SerializePoint(IECPoint point, bool compressed)
+ {
+ var repr = point.Representation;
+ if (compressed)
+ {
+ var serialized = new byte[Secp256k1.SERIALIZED_COMPRESSED_PUBKEY_LENGTH];
+ if (!_inner.PublicKeySerialize(serialized, repr, Flags.SECP256K1_EC_COMPRESSED))
+ {
+ throw new FailedToSerializePointException();
+ }
+
+ return serialized;
+ }
+ else
+ {
+ var serialized = new byte[Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH];
+ if (!_inner.PublicKeySerialize(serialized, repr, Flags.SECP256K1_EC_UNCOMPRESSED))
+ {
+ throw new FailedToSerializePointException();
+ }
+
+ return serialized;
+ }
+ }
+
+
+ public IECPoint Add(IECPoint point1, IECPoint point2)
+ {
+ var output = new byte[Secp256k1.PUBKEY_LENGTH];
+
+ if (!_inner.PublicKeysCombine(output, point1.Representation, point2.Representation))
+ {
+ throw new FailedToCombinePublicKeysException();
+ }
+
+ return Secp256k1Point.FromNative(output);
+ }
+
+ public IECPoint Sub(IECPoint point1, IECPoint point2)
+ {
+ var point2Neg = point2.Representation;
+
+ if (!_inner.PublicKeyNegate(point2Neg))
+ {
+ throw new FailedToNegatePublicKeyException();
+ }
+
+ return Add(point1, Secp256k1Point.FromNative(point2Neg));
+ }
+
+ public IECPoint DeserializePoint(byte[] input)
+ {
+ var pkBytes = new byte[Secp256k1.PUBKEY_LENGTH];
+ if (!_inner.PublicKeyParse(pkBytes, input))
+ {
+ throw new InvalidSerializedPublicKeyException();
+ }
+
+ return Secp256k1Point.FromNative(pkBytes);
+ }
+
+ public IECScalar DeserializeScalar(byte[] input)
+ {
+ var normalized = Helpers.AddLeadingZeros(input, Secp256k1.PRIVKEY_LENGTH)
+ .TakeLast(Secp256k1.PRIVKEY_LENGTH).ToArray();
+ return Secp256k1Scalar.FromNative(normalized);
+ }
+
+ public byte[] GetNonce(IECScalar privateKey, byte[] hash)
+ {
+ var nonce = new byte[Secp256k1.NONCE_LENGTH];
+ if (!_inner.Rfc6979Nonce(nonce, hash, privateKey.Representation, null, null, 0))
+ {
+ throw new FailedToGetNonceException();
+ }
+
+ return nonce;
+ }
+
+ public void Dispose()
+ {
+ _inner.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/src/AElf.Cryptography/Core/Secp256k1Point.cs b/src/AElf.Cryptography/Core/Secp256k1Point.cs
new file mode 100644
index 0000000000..e972727fd8
--- /dev/null
+++ b/src/AElf.Cryptography/Core/Secp256k1Point.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace AElf.Cryptography.Core;
+
+public class Secp256k1Point : IECPoint
+{
+ private readonly byte[] _nativeRep;
+
+ private Secp256k1Point(byte[] nativeRep)
+ {
+ _nativeRep = nativeRep;
+ }
+
+ public static Secp256k1Point FromNative(byte[]nativeRep)
+ {
+ return new Secp256k1Point(nativeRep);
+ }
+ public byte[] Representation
+ {
+ get
+ {
+ var output = new byte[_nativeRep.Length];
+ Buffer.BlockCopy(_nativeRep, 0, output, 0, _nativeRep.Length);
+ return output;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AElf.Cryptography/Core/Secp256k1Scalar.cs b/src/AElf.Cryptography/Core/Secp256k1Scalar.cs
new file mode 100644
index 0000000000..7851503439
--- /dev/null
+++ b/src/AElf.Cryptography/Core/Secp256k1Scalar.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace AElf.Cryptography.Core;
+
+public class Secp256k1Scalar:IECScalar
+{
+ private readonly byte[] _nativeRep;
+
+ private Secp256k1Scalar(byte[] nativeRep)
+ {
+ _nativeRep = nativeRep;
+ }
+
+ public static Secp256k1Scalar FromNative(byte[]nativeRep)
+ {
+ return new Secp256k1Scalar(nativeRep);
+ }
+ public byte[] Representation
+ {
+ get
+ {
+ var output = new byte[_nativeRep.Length];
+ Buffer.BlockCopy(_nativeRep, 0, output, 0, _nativeRep.Length);
+ return output;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/AElf.Cryptography/Core/Sha256HasherFactory.cs b/src/AElf.Cryptography/Core/Sha256HasherFactory.cs
new file mode 100644
index 0000000000..48638040a6
--- /dev/null
+++ b/src/AElf.Cryptography/Core/Sha256HasherFactory.cs
@@ -0,0 +1,12 @@
+using System.Security.Cryptography;
+using AElf.Cryptography.ECVRF;
+
+namespace AElf.Cryptography.Core;
+
+public class Sha256HasherFactory:IHasherFactory
+{
+ public HashAlgorithm Create()
+ {
+ return SHA256.Create();
+ }
+}
\ No newline at end of file
diff --git a/src/AElf.Cryptography/CryptoHelper.cs b/src/AElf.Cryptography/CryptoHelper.cs
index 91abb3a64d..b274636f31 100644
--- a/src/AElf.Cryptography/CryptoHelper.cs
+++ b/src/AElf.Cryptography/CryptoHelper.cs
@@ -2,10 +2,13 @@
using System.Linq;
using System.Security.Cryptography;
using System.Threading;
+using AElf.Cryptography.Core;
using AElf.Cryptography.ECDSA;
+using AElf.Cryptography.ECVRF;
using AElf.Cryptography.Exceptions;
using Secp256k1Net;
using Virgil.Crypto;
+using ECParameters = AElf.Cryptography.ECDSA.ECParameters;
namespace AElf.Cryptography;
@@ -16,6 +19,8 @@ public static class CryptoHelper
// ReaderWriterLock for thread-safe with Secp256k1 APIs
private static readonly ReaderWriterLock Lock = new();
+ private static readonly Vrf Vrf = new(new VrfConfig(0xfe, ECParameters.Curve));
+
static CryptoHelper()
{
AppDomain.CurrentDomain.ProcessExit += (sender, arg) => { Secp256K1.Dispose(); };
@@ -160,4 +165,30 @@ public static byte[] Ecdh(byte[] privateKey, byte[] publicKey)
Lock.ReleaseWriterLock();
}
}
+
+ public static byte[] ECVrfProve(ECKeyPair keyPair, byte[] alpha)
+ {
+ try
+ {
+ Lock.AcquireWriterLock(Timeout.Infinite);
+ return Vrf.Prove(keyPair, alpha);
+ }
+ finally
+ {
+ Lock.ReleaseWriterLock();
+ }
+ }
+
+ public static byte[] ECVrfVerify(byte[] publicKey, byte[] alpha, byte[] pi)
+ {
+ try
+ {
+ Lock.AcquireWriterLock(Timeout.Infinite);
+ return Vrf.Verify(publicKey, alpha, pi);
+ }
+ finally
+ {
+ Lock.ReleaseWriterLock();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/AElf.Cryptography/ECVRF/Exceptions.cs b/src/AElf.Cryptography/ECVRF/Exceptions.cs
new file mode 100644
index 0000000000..471f15a394
--- /dev/null
+++ b/src/AElf.Cryptography/ECVRF/Exceptions.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace AElf.Cryptography.ECVRF;
+
+public class FailedToHashToCurveException : Exception
+{
+}
+
+public class InvalidProofLengthException : Exception
+{
+}
+
+public class InvalidProofException : Exception
+{
+}
\ No newline at end of file
diff --git a/src/AElf.Cryptography/ECVRF/Types.cs b/src/AElf.Cryptography/ECVRF/Types.cs
new file mode 100644
index 0000000000..d9a9975ae4
--- /dev/null
+++ b/src/AElf.Cryptography/ECVRF/Types.cs
@@ -0,0 +1,38 @@
+using System.Security.Cryptography;
+using AElf.Cryptography.Core;
+using AElf.Cryptography.ECDSA;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Math;
+
+namespace AElf.Cryptography.ECVRF;
+
+public struct ProofInput
+{
+ public IECPoint Gamma { get; set; }
+ public BigInteger C { get; set; }
+ public BigInteger S { get; set; }
+}
+
+public struct VrfConfig
+{
+ public byte SuiteString { get; private set; }
+
+ public X9ECParameters EcParameters { get; private set; }
+
+ public VrfConfig(byte suiteString, X9ECParameters ecParameters)
+ {
+ SuiteString = suiteString;
+ EcParameters = ecParameters;
+ }
+}
+
+public interface IHasherFactory
+{
+ HashAlgorithm Create();
+}
+
+public interface IVrf
+{
+ byte[] Prove(ECKeyPair keyPair, byte[] alpha);
+ byte[] Verify(byte[] publicKey, byte[] alpha, byte[] pi);
+}
\ No newline at end of file
diff --git a/src/AElf.Cryptography/ECVRF/Vrf.cs b/src/AElf.Cryptography/ECVRF/Vrf.cs
new file mode 100644
index 0000000000..bbebe61a93
--- /dev/null
+++ b/src/AElf.Cryptography/ECVRF/Vrf.cs
@@ -0,0 +1,204 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using AElf.Cryptography.Core;
+using AElf.Cryptography.ECDSA;
+using Org.BouncyCastle.Math;
+using Secp256k1Net;
+
+namespace AElf.Cryptography.ECVRF;
+
+public class Vrf : IVrf where TCurve : IECCurve, new()
+ where THasherFactory : IHasherFactory, new()
+{
+ private int BitSize => _config.EcParameters.Curve.FieldSize;
+ private int QBitsLength => _config.EcParameters.N.BitLength;
+ private int N => ((BitSize + 1) / 2 + 7) / 8;
+
+ private readonly VrfConfig _config;
+ private readonly IHasherFactory _hasherFactory;
+
+ public Vrf(VrfConfig config)
+ {
+ _config = config;
+ _hasherFactory = new THasherFactory();
+ }
+
+ public byte[] Prove(ECKeyPair keyPair, byte[] alpha)
+ {
+ using var curve = new TCurve();
+ var point = curve.DeserializePoint(keyPair.PublicKey);
+ var hashPoint = HashToCurveTryAndIncrement(point, alpha);
+ var gamma = curve.MultiplyScalar(hashPoint, curve.DeserializeScalar(keyPair.PrivateKey));
+
+ var nonce = Rfc6979Nonce(keyPair, hashPoint);
+ var kB = curve.GetPoint(nonce);
+ var kH = curve.MultiplyScalar(hashPoint, nonce);
+ var c = HashPoints(hashPoint, gamma, kB, kH);
+ var cX = c.Multiply(new BigInteger(1, keyPair.PrivateKey));
+ var s = cX.Add(new BigInteger(1, nonce.Representation)).Mod(_config.EcParameters.N);
+ return EncodeProof(gamma, c, s);
+ }
+
+ public byte[] Verify(byte[] publicKey, byte[] alpha, byte[] pi)
+ {
+ using var curve = new TCurve();
+ var proofInput = DecodeProof(pi);
+
+ var pkPoint = curve.DeserializePoint(publicKey);
+ var hashPoint = HashToCurveTryAndIncrement(pkPoint, alpha);
+ var s = curve.DeserializeScalar(proofInput.S.ToByteArray());
+ var c = curve.DeserializeScalar(proofInput.C.ToByteArray());
+
+ var sB = curve.GetPoint(s);
+ var cY = curve.MultiplyScalar(pkPoint, c);
+ var u = curve.Sub(sB, cY);
+
+ var sH = curve.MultiplyScalar(hashPoint, s);
+ var cGamma = curve.MultiplyScalar(proofInput.Gamma, c);
+ var v = curve.Sub(sH, cGamma);
+
+ var derivedC = HashPoints(hashPoint, proofInput.Gamma, u, v);
+ if (!derivedC.Equals(proofInput.C))
+ {
+ throw new InvalidProofException();
+ }
+
+ return GammaToHash(proofInput.Gamma);
+ }
+
+ public IECPoint HashToCurveTryAndIncrement(IECPoint point, byte[] alpha)
+ {
+ using var curve = new TCurve();
+
+ // Step 1: ctr = 0
+ var ctr = 0;
+
+ // Step 2: PK_string = point_to_string(Y)
+ var pkString = curve.SerializePoint(point, true);
+
+ // Steps 3 ~ 6
+ byte oneString = 0x01;
+ for (; ctr < 256; ctr++)
+ {
+ using var hasher = _hasherFactory.Create();
+ using var stream = new MemoryStream();
+ stream.WriteByte(_config.SuiteString);
+ stream.WriteByte(oneString);
+ stream.Write(pkString);
+ stream.Write(alpha);
+ stream.WriteByte((byte)ctr);
+ stream.Seek(0, SeekOrigin.Begin);
+ var hash = hasher.ComputeHash(stream);
+ var pkSerialized = new byte[Secp256k1.SERIALIZED_COMPRESSED_PUBKEY_LENGTH];
+ pkSerialized[0] = 0x02;
+ Buffer.BlockCopy(hash, 0, pkSerialized, 1, hash.Length);
+ try
+ {
+ var outputPoint = curve.DeserializePoint(pkSerialized);
+ if (_config.EcParameters.Curve.Cofactor.CompareTo(BigInteger.One) > 0)
+ {
+ return curve.MultiplyScalar(outputPoint,
+ curve.DeserializeScalar(_config.EcParameters.Curve.Cofactor.ToByteArray()));
+ }
+
+ return outputPoint;
+ }
+ catch (InvalidSerializedPublicKeyException ex)
+ {
+ // Ignore this exception and try the next ctr
+ }
+ }
+
+ throw new FailedToHashToCurveException();
+ }
+
+ private BigInteger HashPoints(params IECPoint[] points)
+ {
+ using var curve = new TCurve();
+ using var hasher = _hasherFactory.Create();
+ using var stream = new MemoryStream();
+ stream.WriteByte(_config.SuiteString);
+ stream.WriteByte(0x02);
+ foreach (var point in points)
+ {
+ stream.Write(curve.SerializePoint(point, true));
+ }
+
+ stream.Seek(0, SeekOrigin.Begin);
+ var hash = hasher.ComputeHash(stream);
+ var hashTruncated = hash.Take(N).ToArray();
+ return new BigInteger(1, hashTruncated);
+ }
+
+ private byte[] EncodeProof(IECPoint gamma, BigInteger c, BigInteger s)
+ {
+ using var curve = new TCurve();
+ var gammaBytes = curve.SerializePoint(gamma, true);
+ var cBytes = Helpers.Int2Bytes(c, N);
+ var sBytes = Helpers.Int2Bytes(s, (QBitsLength + 7) / 8);
+ var output = new byte[gammaBytes.Length + cBytes.Length + sBytes.Length];
+ Buffer.BlockCopy(gammaBytes, 0, output, 0, gammaBytes.Length);
+ Buffer.BlockCopy(cBytes, 0, output, gammaBytes.Length, cBytes.Length);
+ Buffer.BlockCopy(sBytes, 0, output, gammaBytes.Length + cBytes.Length, sBytes.Length);
+ return output;
+ }
+
+ private ProofInput DecodeProof(byte[] pi)
+ {
+ using var curve = new TCurve();
+ var ptLength = (BitSize + 7) / 8 + 1;
+ var cLength = N;
+ var sLength = (QBitsLength + 7) / 8;
+ if (pi.Length != ptLength + cLength + sLength)
+ {
+ throw new InvalidProofLengthException();
+ }
+
+ var gammaPoint = curve.DeserializePoint(pi.Take(ptLength).ToArray());
+ var c = new BigInteger(1, pi.Skip(ptLength).Take(cLength).ToArray());
+ var s = new BigInteger(1, pi.TakeLast(sLength).ToArray());
+ return new ProofInput()
+ {
+ Gamma = gammaPoint,
+ C = c,
+ S = s
+ };
+ }
+
+ private byte[] GammaToHash(IECPoint gamma)
+ {
+ using var curve = new TCurve();
+
+ var gammaCof = gamma;
+ if (_config.EcParameters.Curve.Cofactor.CompareTo(BigInteger.One) > 0)
+ {
+ gammaCof = curve.MultiplyScalar(gamma,
+ curve.DeserializeScalar(_config.EcParameters.Curve.Cofactor.ToByteArray()));
+ }
+
+ var gammaCofBytes = curve.SerializePoint(gammaCof, true);
+ using var hasher = _hasherFactory.Create();
+ using var stream = new MemoryStream();
+ stream.WriteByte(_config.SuiteString);
+ stream.WriteByte(0x03);
+ stream.Write(gammaCofBytes);
+ stream.Seek(0, SeekOrigin.Begin);
+ return hasher.ComputeHash(stream);
+ }
+
+ private IECScalar Rfc6979Nonce(ECKeyPair keyPair, IECPoint hashPoint)
+ {
+ using var curve = new TCurve();
+ using var hasher = _hasherFactory.Create();
+ var roLen = (QBitsLength + 7) / 8;
+ var hBytes = curve.SerializePoint(hashPoint, true);
+
+ var hash = hasher.ComputeHash(hBytes);
+ var bh = Helpers.Bits2Bytes(hash, _config.EcParameters.N, roLen);
+
+ var nonce = curve.GetNonce(curve.DeserializeScalar(keyPair.PrivateKey), bh);
+ return curve.DeserializeScalar(nonce);
+ }
+}
\ No newline at end of file
diff --git a/src/AElf.Kernel.Consensus.AEDPoS/AElf.Kernel.Consensus.AEDPoS.csproj b/src/AElf.Kernel.Consensus.AEDPoS/AElf.Kernel.Consensus.AEDPoS.csproj
index beb55cf877..fc3fc47069 100644
--- a/src/AElf.Kernel.Consensus.AEDPoS/AElf.Kernel.Consensus.AEDPoS.csproj
+++ b/src/AElf.Kernel.Consensus.AEDPoS/AElf.Kernel.Consensus.AEDPoS.csproj
@@ -1,5 +1,5 @@
-
+
net6.0
@@ -15,7 +15,7 @@
-
+
@@ -31,7 +31,7 @@
-
+
diff --git a/src/AElf.Kernel.Consensus.AEDPoS/Application/AEDPoSInformationProvider.cs b/src/AElf.Kernel.Consensus.AEDPoS/Application/AEDPoSInformationProvider.cs
index a893dd3eb5..971ed6bead 100644
--- a/src/AElf.Kernel.Consensus.AEDPoS/Application/AEDPoSInformationProvider.cs
+++ b/src/AElf.Kernel.Consensus.AEDPoS/Application/AEDPoSInformationProvider.cs
@@ -4,6 +4,7 @@
using AElf.Contracts.Consensus.AEDPoS;
using AElf.Kernel.Consensus.Application;
using AElf.Kernel.SmartContract.Application;
+using AElf.Types;
using Google.Protobuf.WellKnownTypes;
namespace AElf.Kernel.Consensus.AEDPoS.Application;
@@ -22,7 +23,7 @@ public AEDPoSInformationProvider(
_consensusReaderContextService = consensusReaderContextService;
}
- public async Task> GetCurrentMinerList(ChainContext chainContext)
+ public async Task> GetCurrentMinerListAsync(ChainContext chainContext)
{
var contractReaderContext =
await _consensusReaderContextService.GetContractReaderContextAsync(chainContext);
diff --git a/src/AElf.Kernel.Consensus.AEDPoS/Application/AEDPoSTriggerInformationProvider.cs b/src/AElf.Kernel.Consensus.AEDPoS/Application/AEDPoSTriggerInformationProvider.cs
index 255d1549f0..4801f78af1 100644
--- a/src/AElf.Kernel.Consensus.AEDPoS/Application/AEDPoSTriggerInformationProvider.cs
+++ b/src/AElf.Kernel.Consensus.AEDPoS/Application/AEDPoSTriggerInformationProvider.cs
@@ -1,6 +1,8 @@
+using System.Threading.Tasks;
using AElf.Contracts.Consensus.AEDPoS;
using AElf.Kernel.Account.Application;
using AElf.Kernel.Consensus.Application;
+using AElf.Types;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using Microsoft.Extensions.Logging;
@@ -14,13 +16,15 @@ internal class AEDPoSTriggerInformationProvider : ITriggerInformationProvider
private readonly IAccountService _accountService;
private readonly IInValueCache _inValueCache;
private readonly ISecretSharingService _secretSharingService;
+ private readonly IRandomNumberProvider _randomNumberProvider;
public AEDPoSTriggerInformationProvider(IAccountService accountService,
- ISecretSharingService secretSharingService, IInValueCache inValueCache)
+ ISecretSharingService secretSharingService, IInValueCache inValueCache, IRandomNumberProvider randomNumberProvider)
{
_accountService = accountService;
_secretSharingService = secretSharingService;
_inValueCache = inValueCache;
+ _randomNumberProvider = randomNumberProvider;
Logger = NullLogger.Instance;
}
@@ -70,13 +74,16 @@ public BytesValue GetTriggerInformationForBlockHeaderExtraData(BytesValue consen
}.ToBytesValue();
}
- public BytesValue GetTriggerInformationForConsensusTransactions(BytesValue consensusCommandBytes)
+ public BytesValue GetTriggerInformationForConsensusTransactions(IChainContext chainContext, BytesValue consensusCommandBytes)
{
+ var randomProof = AsyncHelper.RunSync(async ()=> await _randomNumberProvider.GenerateRandomProofAsync(chainContext));
+
if (consensusCommandBytes == null)
return new AElfConsensusTriggerInformation
{
Pubkey = Pubkey,
- Behaviour = AElfConsensusBehaviour.UpdateValue
+ Behaviour = AElfConsensusBehaviour.UpdateValue,
+ RandomNumber = ByteString.CopyFrom(randomProof)
}.ToBytesValue();
var command = consensusCommandBytes.ToConsensusCommand();
@@ -90,7 +97,8 @@ public BytesValue GetTriggerInformationForConsensusTransactions(BytesValue conse
Pubkey = Pubkey,
InValue = inValue,
PreviousInValue = _inValueCache.GetInValue(hint.PreviousRoundId),
- Behaviour = hint.Behaviour
+ Behaviour = hint.Behaviour,
+ RandomNumber = ByteString.CopyFrom(randomProof)
};
var secretPieces = _secretSharingService.GetEncryptedPieces(hint.RoundId);
@@ -111,7 +119,8 @@ public BytesValue GetTriggerInformationForConsensusTransactions(BytesValue conse
return new AElfConsensusTriggerInformation
{
Pubkey = Pubkey,
- Behaviour = hint.Behaviour
+ Behaviour = hint.Behaviour,
+ RandomNumber = ByteString.CopyFrom(randomProof)
}.ToBytesValue();
}
}
\ No newline at end of file
diff --git a/src/AElf.Kernel.Consensus.AEDPoS/Application/IAEDPoSInformationProvider.cs b/src/AElf.Kernel.Consensus.AEDPoS/Application/IAEDPoSInformationProvider.cs
index 0eb4d0f7cc..73dcb641fe 100644
--- a/src/AElf.Kernel.Consensus.AEDPoS/Application/IAEDPoSInformationProvider.cs
+++ b/src/AElf.Kernel.Consensus.AEDPoS/Application/IAEDPoSInformationProvider.cs
@@ -1,10 +1,11 @@
using System.Collections.Generic;
using System.Threading.Tasks;
+using AElf.Types;
namespace AElf.Kernel.Consensus.AEDPoS.Application;
// ReSharper disable once InconsistentNaming
public interface IAEDPoSInformationProvider
{
- Task> GetCurrentMinerList(ChainContext chainContext);
+ Task> GetCurrentMinerListAsync(ChainContext chainContext);
}
\ No newline at end of file
diff --git a/src/AElf.Kernel.Consensus.AEDPoS/Application/IRandomNumberProvider.cs b/src/AElf.Kernel.Consensus.AEDPoS/Application/IRandomNumberProvider.cs
new file mode 100644
index 0000000000..cd21577534
--- /dev/null
+++ b/src/AElf.Kernel.Consensus.AEDPoS/Application/IRandomNumberProvider.cs
@@ -0,0 +1,47 @@
+using System.Threading.Tasks;
+using AElf.Contracts.Consensus.AEDPoS;
+using AElf.Kernel.Account.Application;
+using AElf.Kernel.Consensus.Application;
+using AElf.Kernel.SmartContract.Application;
+using AElf.Types;
+using Google.Protobuf.WellKnownTypes;
+using Volo.Abp.DependencyInjection;
+
+namespace AElf.Kernel.Consensus.AEDPoS.Application;
+
+public interface IRandomNumberProvider
+{
+ Task GenerateRandomProofAsync(IChainContext chainContext);
+}
+
+internal class RandomNumberProvider : IRandomNumberProvider, ITransientDependency
+{
+ private readonly IAccountService _accountService;
+ private readonly IConsensusReaderContextService _consensusReaderContextService;
+ private readonly IContractReaderFactory _contractReaderFactory;
+
+ public RandomNumberProvider(IAccountService accountService,
+ IConsensusReaderContextService consensusReaderContextService,
+ IContractReaderFactory contractReaderFactory)
+ {
+ _accountService = accountService;
+ _consensusReaderContextService = consensusReaderContextService;
+ _contractReaderFactory = contractReaderFactory;
+ }
+
+ public async Task GenerateRandomProofAsync(IChainContext chainContext)
+ {
+ var previousRandomHash = chainContext.BlockHeight == AElfConstants.GenesisBlockHeight
+ ? Hash.Empty
+ : await GetRandomHashAsync(chainContext, chainContext.BlockHeight);
+ return await _accountService.ECVrfProveAsync(previousRandomHash.ToByteArray());
+ }
+
+ private async Task GetRandomHashAsync(IChainContext chainContext, long blockHeight)
+ {
+ var contractReaderContext =
+ await _consensusReaderContextService.GetContractReaderContextAsync(chainContext);
+ return await _contractReaderFactory
+ .Create(contractReaderContext).GetRandomHash.CallAsync(new Int64Value { Value = blockHeight });
+ }
+}
diff --git a/src/AElf.Kernel.Consensus.Core/Application/ConsensusService.cs b/src/AElf.Kernel.Consensus.Core/Application/ConsensusService.cs
index 680a36dfb5..50a75d9f90 100644
--- a/src/AElf.Kernel.Consensus.Core/Application/ConsensusService.cs
+++ b/src/AElf.Kernel.Consensus.Core/Application/ConsensusService.cs
@@ -215,7 +215,7 @@ public async Task> GenerateConsensusTransactionsAsync(ChainCon
.Create(contractReaderContext)
.GenerateConsensusTransactions
.CallAsync(_triggerInformationProvider.GetTriggerInformationForConsensusTransactions(
- _consensusCommand.ToBytesValue())))
+ chainContext, _consensusCommand.ToBytesValue())))
.Transactions
.ToList();
diff --git a/src/AElf.Kernel.Consensus.Core/Application/ITriggerInformationProvider.cs b/src/AElf.Kernel.Consensus.Core/Application/ITriggerInformationProvider.cs
index 26567a68b5..7ba7d31e5c 100644
--- a/src/AElf.Kernel.Consensus.Core/Application/ITriggerInformationProvider.cs
+++ b/src/AElf.Kernel.Consensus.Core/Application/ITriggerInformationProvider.cs
@@ -7,5 +7,5 @@ public interface ITriggerInformationProvider
{
BytesValue GetTriggerInformationForConsensusCommand(BytesValue consensusCommandBytes);
BytesValue GetTriggerInformationForBlockHeaderExtraData(BytesValue consensusCommandBytes);
- BytesValue GetTriggerInformationForConsensusTransactions(BytesValue consensusCommandBytes);
+ BytesValue GetTriggerInformationForConsensusTransactions(IChainContext chainContext, BytesValue consensusCommandBytes);
}
\ No newline at end of file
diff --git a/src/AElf.Kernel.Core/Account/Application/IAccountService.cs b/src/AElf.Kernel.Core/Account/Application/IAccountService.cs
index fa47a8ecc5..523dee30cb 100644
--- a/src/AElf.Kernel.Core/Account/Application/IAccountService.cs
+++ b/src/AElf.Kernel.Core/Account/Application/IAccountService.cs
@@ -1,4 +1,6 @@
using AElf.Cryptography;
+using AElf.Cryptography.ECDSA;
+using AElf.Cryptography.ECVRF;
using AElf.Kernel.Account.Infrastructure;
namespace AElf.Kernel.Account.Application;
@@ -9,6 +11,7 @@ public interface IAccountService
Task GetPublicKeyAsync();
Task EncryptMessageAsync(byte[] receiverPublicKey, byte[] plainMessage);
Task DecryptMessageAsync(byte[] senderPublicKey, byte[] cipherMessage);
+ Task ECVrfProveAsync(byte[] message);
}
public static class AccountServiceExtensions
@@ -53,4 +56,9 @@ public Task DecryptMessageAsync(byte[] senderPublicKey, byte[] cipherMes
return Task.FromResult(CryptoHelper.DecryptMessage(senderPublicKey,
_ecKeyPairProvider.GetKeyPair().PrivateKey, cipherMessage));
}
+
+ public Task ECVrfProveAsync(byte[] message)
+ {
+ return Task.FromResult(CryptoHelper.ECVrfProve((ECKeyPair)_ecKeyPairProvider.GetKeyPair(), message));
+ }
}
\ No newline at end of file
diff --git a/src/AElf.Kernel.SmartContract.Shared/ISmartContractBridgeContext.cs b/src/AElf.Kernel.SmartContract.Shared/ISmartContractBridgeContext.cs
index a7f5fbcf99..473ccfc932 100644
--- a/src/AElf.Kernel.SmartContract.Shared/ISmartContractBridgeContext.cs
+++ b/src/AElf.Kernel.SmartContract.Shared/ISmartContractBridgeContext.cs
@@ -88,6 +88,8 @@ Address ConvertVirtualAddressToContractAddressWithContractHashName(Hash virtualA
long ConvertHashToInt64(Hash hash, long start = 0, long end = long.MaxValue);
object ValidateStateSize(object obj);
+
+ bool ECVrfVerify(byte[] pubKey, byte[] alpha, byte[] pi, out byte[] beta);
}
[Serializable]
diff --git a/src/AElf.Kernel.SmartContract/HostSmartContractBridgeContext.cs b/src/AElf.Kernel.SmartContract/HostSmartContractBridgeContext.cs
index 144f1aa0a5..53cd03ed12 100644
--- a/src/AElf.Kernel.SmartContract/HostSmartContractBridgeContext.cs
+++ b/src/AElf.Kernel.SmartContract/HostSmartContractBridgeContext.cs
@@ -349,4 +349,19 @@ public byte[] RecoverPublicKey(byte[] signature, byte[] hash)
var cabBeRecovered = CryptoHelper.RecoverPublicKey(signature, hash, out var publicKey);
return !cabBeRecovered ? null : publicKey;
}
+
+ public bool ECVrfVerify(byte[] pubKey, byte[] alpha, byte[] pi, out byte[] beta)
+ {
+ try
+ {
+ beta = CryptoHelper.ECVrfVerify(pubKey, alpha, pi);
+ }
+ catch
+ {
+ beta = null;
+ return false;
+ }
+
+ return true;
+ }
}
\ No newline at end of file
diff --git a/src/AElf.OS/Account/Application/AccountService.cs b/src/AElf.OS/Account/Application/AccountService.cs
index 9e2e2400d4..ec1193c564 100644
--- a/src/AElf.OS/Account/Application/AccountService.cs
+++ b/src/AElf.OS/Account/Application/AccountService.cs
@@ -2,6 +2,7 @@
using System.Threading.Tasks;
using AElf.Cryptography;
using AElf.Cryptography.ECDSA;
+using AElf.Cryptography.ECVRF;
using AElf.Kernel.Account.Application;
using AElf.OS.Account.Infrastructure;
using AElf.Types;
@@ -43,6 +44,12 @@ public async Task DecryptMessageAsync(byte[] senderPublicKey, byte[] cip
cipherMessage);
}
+ public async Task ECVrfProveAsync(byte[] message)
+ {
+ var keyPair = await GetAccountKeyPairAsync();
+ return CryptoHelper.ECVrfProve(keyPair, message);
+ }
+
public async Task GetAccountAsync()
{
var publicKey = (await GetAccountKeyPairAsync()).PublicKey;
diff --git a/src/AElf.Sdk.CSharp/CSharpSmartContractContext.cs b/src/AElf.Sdk.CSharp/CSharpSmartContractContext.cs
index 2f56f80931..ae91d612d8 100644
--- a/src/AElf.Sdk.CSharp/CSharpSmartContractContext.cs
+++ b/src/AElf.Sdk.CSharp/CSharpSmartContractContext.cs
@@ -372,4 +372,9 @@ public Address ConvertVirtualAddressToContractAddressWithContractHashName(Hash v
return SmartContractBridgeContextImplementation.ConvertVirtualAddressToContractAddressWithContractHashName(
virtualAddress);
}
+
+ public bool ECVrfVerify(byte[] pubKey, byte[] alpha, byte[] pi, out byte[] beta)
+ {
+ return SmartContractBridgeContextImplementation.ECVrfVerify(pubKey, alpha, pi, out beta);
+ }
}
\ No newline at end of file
diff --git a/src/AElf.WebApp.Application.Chain/Services/TransactionResultAppService.cs b/src/AElf.WebApp.Application.Chain/Services/TransactionResultAppService.cs
index 1c5fdabe4c..08552f42e5 100644
--- a/src/AElf.WebApp.Application.Chain/Services/TransactionResultAppService.cs
+++ b/src/AElf.WebApp.Application.Chain/Services/TransactionResultAppService.cs
@@ -101,19 +101,9 @@ public async Task GetTransactionResultAsync(string transac
return output;
}
-
- var methodDescriptor =
- await GetContractMethodDescriptorAsync(transaction!.To, transaction.MethodName, false);
-
- if (methodDescriptor != null)
- {
- var parameters = methodDescriptor.InputType.Parser.ParseFrom(transaction.Params);
- if (!IsValidMessage(parameters))
- throw new UserFriendlyException(Error.Message[Error.InvalidParams], Error.InvalidParams.ToString());
-
- output.Transaction.Params = JsonFormatter.ToDiagnosticString(parameters);
- }
-
+
+ await FormatTransactionParamsAsync(output.Transaction, transaction.Params);
+
return output;
}
@@ -244,17 +234,7 @@ private async Task GetTransactionResultDto(Hash transactio
transactionResultDto.Transaction = _objectMapper.Map(transaction);
transactionResultDto.TransactionSize = transaction.CalculateSize();
- var methodDescriptor =
- await GetContractMethodDescriptorAsync(transaction.To, transaction.MethodName, false);
-
- if (methodDescriptor != null)
- {
- var parameters = methodDescriptor.InputType.Parser.ParseFrom(transaction.Params);
- if (!IsValidMessage(parameters))
- throw new UserFriendlyException(Error.Message[Error.InvalidParams], Error.InvalidParams.ToString());
-
- transactionResultDto.Transaction.Params = JsonFormatter.ToDiagnosticString(parameters);
- }
+ await FormatTransactionParamsAsync(transactionResultDto.Transaction, transaction.Params);
return transactionResultDto;
}
@@ -304,20 +284,6 @@ private Hash GetHashCombiningTransactionAndStatus(Hash txId,
return HashHelper.ComputeFrom(rawBytes);
}
- private bool IsValidMessage(IMessage message)
- {
- try
- {
- JsonFormatter.ToDiagnosticString(message);
- }
- catch
- {
- return false;
- }
-
- return true;
- }
-
private async Task GetContractMethodDescriptorAsync(Address contractAddress,
string methodName, bool throwException = true)
{
@@ -331,4 +297,23 @@ private async Task GetContractMethodDescriptorAsync(Address co
return await _transactionReadOnlyExecutionService.GetContractMethodDescriptorAsync(chainContext,
contractAddress, methodName, throwException);
}
+
+ private async Task FormatTransactionParamsAsync(TransactionDto transaction, ByteString @params)
+ {
+ var methodDescriptor =
+ await GetContractMethodDescriptorAsync(Address.FromBase58(transaction.To), transaction.MethodName, false);
+
+ if (methodDescriptor == null)
+ return;
+
+ try
+ {
+ var parameters = methodDescriptor.InputType.Parser.ParseFrom(@params);
+ transaction.Params = JsonFormatter.ToDiagnosticString(parameters);;
+ }
+ catch (Exception exception)
+ {
+ Logger.LogError(exception, "Failed to parse transaction params: {params}", transaction.Params);
+ }
+ }
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/AEDPoSExtensionDemoTestBase.cs b/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/AEDPoSExtensionDemoTestBase.cs
index 368cc56084..a3550cb210 100644
--- a/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/AEDPoSExtensionDemoTestBase.cs
+++ b/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/AEDPoSExtensionDemoTestBase.cs
@@ -81,8 +81,12 @@ internal void InitialContracts()
internal void InitialAcs3Stubs()
{
foreach (var initialKeyPair in MissionedECKeyPairs.InitialKeyPairs)
- ParliamentStubs.Add(GetTester(
- ContractAddresses[ParliamentSmartContractAddressNameProvider.Name], initialKeyPair));
+ {
+ var parliamentStub = GetTester(
+ ContractAddresses[ParliamentSmartContractAddressNameProvider.Name], initialKeyPair);
+
+ ParliamentStubs.Add(parliamentStub);
+ }
}
internal async Task
diff --git a/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/AEDPoSExtensionTests.cs b/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/AEDPoSExtensionTests.cs
index 8840133e89..5f7d8d1c5f 100644
--- a/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/AEDPoSExtensionTests.cs
+++ b/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/AEDPoSExtensionTests.cs
@@ -4,10 +4,14 @@
using System.Threading.Tasks;
using AElf.Contracts.Consensus.AEDPoS;
using AElf.Contracts.MultiToken;
+using AElf.Contracts.Parliament;
using AElf.ContractTestKit;
using AElf.ContractTestKit.AEDPoSExtension;
+using AElf.CSharp.Core.Extension;
using AElf.Kernel;
using AElf.Kernel.Consensus;
+using AElf.Kernel.Token;
+using AElf.Standards.ACS3;
using AElf.Types;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
@@ -23,6 +27,7 @@ public class AEDPoSExtensionTests : AEDPoSExtensionDemoTestBase
public async Task Demo_Test()
{
InitialContracts();
+ InitialAcs3Stubs();
// Check round information after initialization.
{
@@ -42,15 +47,31 @@ public async Task Demo_Test()
// And this will produce one block with one transaction.
// This transaction will call Create method of Token Contract.
- var createTokenTransaction = TokenStub.Create.GetTransaction(new CreateInput
+ await ParliamentStubs.First().Initialize.SendAsync(new InitializeInput
{
- Symbol = "ELF",
- Decimals = 8,
- TokenName = "Test",
- Issuer = Accounts[0].Address,
- IsBurnable = true,
- TotalSupply = 1_000_000_000_00000000
+ ProposerAuthorityRequired = false,
+ PrivilegedProposer = Address.FromPublicKey(MissionedECKeyPairs.InitialKeyPairs.First().PublicKey)
+ });
+ var defaultOrganizationAddress =
+ await ParliamentStubs.First().GetDefaultOrganizationAddress.CallAsync(new Empty());
+ await ParliamentReachAnAgreementAsync(new CreateProposalInput
+ {
+ ToAddress = ContractAddresses[TokenSmartContractAddressNameProvider.Name],
+ ContractMethodName = nameof(TokenStub.Create),
+ Params = new CreateInput
+ {
+ Symbol = "ELF",
+ Decimals = 8,
+ TokenName = "Test",
+ Issuer = Accounts[0].Address,
+ Owner = Accounts[0].Address,
+ IsBurnable = true,
+ TotalSupply = 1_000_000_000_00000000
+ }.ToByteString(),
+ ExpiredTime = TimestampHelper.GetUtcNow().AddDays(1),
+ OrganizationAddress = defaultOrganizationAddress
});
+
const long issueTokenAmount = 10_0000_00000000;
var issueToAddress = Address.FromPublicKey(MissionedECKeyPairs.InitialKeyPairs.First().PublicKey);
var issueTokenTransaction = TokenStub.Issue.GetTransaction(new IssueInput
@@ -61,12 +82,11 @@ public async Task Demo_Test()
});
await BlockMiningService.MineBlockAsync(new List
{
- createTokenTransaction,
issueTokenTransaction
});
var createTokenTransactionTrace =
- TransactionTraceProvider.GetTransactionTrace(createTokenTransaction.GetHash());
+ TransactionTraceProvider.GetTransactionTrace(issueTokenTransaction.GetHash());
createTokenTransactionTrace.ExecutionStatus.ShouldBe(ExecutionStatus.Executed);
// Check whether previous Create transaction successfully executed.
diff --git a/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/MaximumMinersCountTests.cs b/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/MaximumMinersCountTests.cs
index 858b0d890f..69f4d0c7d9 100644
--- a/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/MaximumMinersCountTests.cs
+++ b/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/MaximumMinersCountTests.cs
@@ -3,11 +3,13 @@
using System.Threading.Tasks;
using AElf.Contracts.Parliament;
using AElf.ContractTestKit;
+using AElf.ContractTestKit.AEDPoSExtension;
using AElf.CSharp.Core.Extension;
using AElf.Kernel;
using AElf.Kernel.Consensus;
using AElf.Kernel.Proposal;
using AElf.Standards.ACS3;
+using AElf.Types;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using Microsoft.Extensions.DependencyInjection;
@@ -30,7 +32,11 @@ public async Task SetMaximumMinersCountTest(int targetMinersCount)
await BlockMiningService.MineBlockToNextTermAsync();
InitialAcs3Stubs();
- await ParliamentStubs.First().Initialize.SendAsync(new InitializeInput());
+ await ParliamentStubs.First().Initialize.SendAsync(new InitializeInput
+ {
+ ProposerAuthorityRequired = false,
+ PrivilegedProposer = Address.FromPublicKey(MissionedECKeyPairs.InitialKeyPairs.First().PublicKey)
+ });
var defaultOrganizationAddress =
await ParliamentStubs.First().GetDefaultOrganizationAddress.CallAsync(new Empty());
await ParliamentReachAnAgreementAsync(new CreateProposalInput
diff --git a/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/SideChainConsensusInformationTest.cs b/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/SideChainConsensusInformationTest.cs
index dd1ef0f753..8686d6fbd0 100644
--- a/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/SideChainConsensusInformationTest.cs
+++ b/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/SideChainConsensusInformationTest.cs
@@ -3,10 +3,15 @@
using System.Threading.Tasks;
using AElf.Contracts.Consensus.AEDPoS;
using AElf.Contracts.MultiToken;
+using AElf.Contracts.Parliament;
using AElf.ContractTestKit;
using AElf.ContractTestKit.AEDPoSExtension;
+using AElf.CSharp.Core.Extension;
+using AElf.Kernel;
using AElf.Kernel.Consensus;
+using AElf.Kernel.Token;
using AElf.Standards.ACS10;
+using AElf.Standards.ACS3;
using AElf.Types;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
@@ -31,6 +36,7 @@ public async Task UpdateInformationFromCrossChainTest()
{
SetToSideChain();
InitialContracts();
+ InitialAcs3Stubs();
var mockedCrossChain = SampleAccount.Accounts.Last();
var mockedCrossChainStub =
GetTester(
@@ -51,6 +57,11 @@ public async Task UpdateInformationFromCrossChainTest()
}
};
+ await ParliamentStubs.First().Initialize.SendAsync(new InitializeInput
+ {
+ ProposerAuthorityRequired = false,
+ PrivilegedProposer = Address.FromPublicKey(MissionedECKeyPairs.InitialKeyPairs.First().PublicKey)
+ });
await CreateAndIssueToken("ELF");
await CreateAndIssueToken("READ");
await TokenStub.Transfer.SendAsync(new TransferInput
@@ -78,15 +89,26 @@ await mockedCrossChainStub.UpdateInformationFromCrossChain.SendAsync(new BytesVa
private async Task CreateAndIssueToken(string symbol)
{
- var createTokenTransaction = TokenStub.Create.GetTransaction(new CreateInput
+ var defaultOrganizationAddress =
+ await ParliamentStubs.First().GetDefaultOrganizationAddress.CallAsync(new Empty());
+ await ParliamentReachAnAgreementAsync(new CreateProposalInput
{
- Symbol = symbol,
- Decimals = 8,
- TokenName = "Test",
- Issuer = Accounts[0].Address,
- IsBurnable = true,
- TotalSupply = 1_000_000_000_00000000
+ ToAddress = ContractAddresses[TokenSmartContractAddressNameProvider.Name],
+ ContractMethodName = nameof(TokenStub.Create),
+ Params = new CreateInput
+ {
+ Symbol = symbol,
+ Decimals = 8,
+ TokenName = "Test",
+ Issuer = Accounts[0].Address,
+ Owner = Accounts[0].Address,
+ IsBurnable = true,
+ TotalSupply = 1_000_000_000_00000000
+ }.ToByteString(),
+ ExpiredTime = TimestampHelper.GetUtcNow().AddDays(1),
+ OrganizationAddress = defaultOrganizationAddress
});
+
const long issueTokenAmount = 10_0000_00000000;
var issueToAddress = Address.FromPublicKey(MissionedECKeyPairs.InitialKeyPairs.First().PublicKey);
var issueTokenTransaction = TokenStub.Issue.GetTransaction(new IssueInput
@@ -97,7 +119,7 @@ private async Task CreateAndIssueToken(string symbol)
});
await BlockMiningService.MineBlockAsync(new List
{
- createTokenTransaction,
+ // createTokenTransaction,
issueTokenTransaction
});
}
diff --git a/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/SideChainRentFeeTestBase.cs b/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/SideChainRentFeeTestBase.cs
index 9d505d89d1..096c82d929 100644
--- a/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/SideChainRentFeeTestBase.cs
+++ b/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/SideChainRentFeeTestBase.cs
@@ -76,7 +76,7 @@ protected void DeployContracts()
TokenSmartContractAddressNameProvider.Name,
DefaultSenderKeyPair));
TokenContractStub = GetTokenContractTester(DefaultSenderKeyPair);
- AsyncHelper.RunSync(async () => await InitializeTokenAsync());
+ // AsyncHelper.RunSync(async () => await InitializeTokenAsync());
ParliamentContractAddress = AsyncHelper.RunSync(() =>
DeploySystemSmartContract(
@@ -141,27 +141,6 @@ internal AEDPoSContractImplContainer.AEDPoSContractImplStub GetConsensusContract
return GetTester(ConsensusContractAddress, keyPair);
}
- private async Task InitializeTokenAsync()
- {
- const long totalSupply = 100_000_000;
- await TokenContractStub.Create.SendAsync(new CreateInput
- {
- Symbol = NativeTokenSymbol,
- Decimals = 2,
- IsBurnable = true,
- TokenName = "elf token",
- TotalSupply = totalSupply,
- Issuer = DefaultSender
- });
- await TokenContractStub.Issue.SendAsync(new IssueInput
- {
- Symbol = NativeTokenSymbol,
- Amount = totalSupply - 20 * 100_000L,
- To = DefaultSender,
- Memo = "Issue token to default user."
- });
- }
-
private async Task InitializeParliamentContract()
{
var initializeResult = await ParliamentContractStub.Initialize.SendAsync(new InitializeInput
diff --git a/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/SideChainSideChainRentFeeTest.cs b/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/SideChainSideChainRentFeeTest.cs
index e9b625eb32..ef56dc42c5 100644
--- a/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/SideChainSideChainRentFeeTest.cs
+++ b/test/AElf.Contracts.AEDPoSExtension.Demo.Tests/SideChainSideChainRentFeeTest.cs
@@ -293,12 +293,13 @@ await TokenContractStub.GetBalance.SendAsync(new GetBalanceInput // each tx set
private async Task InitialTokenContractAsync(bool issueToken = true)
{
- await CreateTokenAsync("CPU", ResourceSupply, issueToken);
- await CreateTokenAsync("RAM", ResourceSupply, issueToken);
- await CreateTokenAsync("DISK", ResourceSupply, issueToken);
- await CreateTokenAsync("NET", ResourceSupply, issueToken);
var defaultParliamentOrganization =
await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
+ await CreateTokenAsync("ELF", ResourceSupply, issueToken, defaultParliamentOrganization);
+ await CreateTokenAsync("CPU", ResourceSupply, issueToken, defaultParliamentOrganization);
+ await CreateTokenAsync("RAM", ResourceSupply, issueToken, defaultParliamentOrganization);
+ await CreateTokenAsync("DISK", ResourceSupply, issueToken, defaultParliamentOrganization);
+ await CreateTokenAsync("NET", ResourceSupply, issueToken, defaultParliamentOrganization);
var setSideChainCreatorProposalInput = new InitializeFromParentChainInput
{
ResourceAmount =
@@ -331,18 +332,20 @@ await UpdateSideChainRentalDefaultProposalAsync(
nameof(TokenContractImplContainer.TokenContractImplStub.UpdateRental), updateRentalInput);
}
- private async Task CreateTokenAsync(string symbol, long supply, bool issueToken)
+ private async Task CreateTokenAsync(string symbol, long supply, bool issueToken, Address organizationAddress)
{
- await TokenContractStub.Create.SendAsync(new CreateInput
- {
- Decimals = 8,
- Issuer = Creator,
- Symbol = symbol,
- TotalSupply = supply,
- IsBurnable = true,
- TokenName = $"{symbol} token."
- });
-
+ await ParliamentReachAnAgreementAsync(TokenContractAddress, organizationAddress,
+ nameof(TokenContractStub.Create), new CreateInput
+ {
+ Decimals = 8,
+ Issuer = Creator,
+ Symbol = symbol,
+ TotalSupply = supply,
+ IsBurnable = true,
+ TokenName = $"{symbol} token.",
+ Owner = Creator
+ });
+
if (!issueToken) return;
await TokenContractStub.Issue.SendAsync(new IssueInput
diff --git a/test/AElf.Contracts.Association.Tests/AssociationContractTests.cs b/test/AElf.Contracts.Association.Tests/AssociationContractTests.cs
index ad6ff414d9..0da11d0fa3 100644
--- a/test/AElf.Contracts.Association.Tests/AssociationContractTests.cs
+++ b/test/AElf.Contracts.Association.Tests/AssociationContractTests.cs
@@ -943,13 +943,22 @@ public async Task SetMethodFee_Fail_Test()
var tokenSymbol = "DLS";
var invalidMethodFees = GetValidMethodFees();
invalidMethodFees.Fees[0].Symbol = tokenSymbol;
- await TokenContractStub.Create.SendAsync(new CreateInput
- {
- Symbol = tokenSymbol,
- TokenName = "name",
- Issuer = DefaultSender,
- TotalSupply = 1000_000
- });
+
+ var defaultOrganization = await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
+
+ var proposalId = await CreateFeeProposalAsync(TokenContractAddress,
+ defaultOrganization, nameof(TokenContractStub.Create), new CreateInput
+ {
+ Symbol = tokenSymbol,
+ TokenName = "name",
+ Issuer = DefaultSender,
+ TotalSupply = 1000_000,
+ Owner = DefaultSender,
+ });
+
+ await ApproveWithMinersAsync(proposalId);
+ await ParliamentContractStub.Release.SendAsync(proposalId);
+
var ret = await AssociationContractStub.SetMethodFee.SendWithExceptionAsync(invalidMethodFees);
ret.TransactionResult.Error.ShouldContain($"Token {tokenSymbol} cannot set as method fee.");
}
diff --git a/test/AElf.Contracts.Association.Tests/UnitTestTokenContractInitializationProvider.cs b/test/AElf.Contracts.Association.Tests/UnitTestTokenContractInitializationProvider.cs
index aa110100ca..99cd591ce1 100644
--- a/test/AElf.Contracts.Association.Tests/UnitTestTokenContractInitializationProvider.cs
+++ b/test/AElf.Contracts.Association.Tests/UnitTestTokenContractInitializationProvider.cs
@@ -38,6 +38,7 @@ public override List GetInitializeMethodList(b
{
Decimals = _economicOptions.Decimals,
Issuer = address,
+ Owner = address,
IsBurnable = _economicOptions.IsBurnable,
Symbol = _economicOptions.Symbol,
TokenName = _economicOptions.TokenName,
diff --git a/test/AElf.Contracts.Configuration.Tests/ConfigurationContractTest.cs b/test/AElf.Contracts.Configuration.Tests/ConfigurationContractTest.cs
index 2fb4b58217..f0876ac70f 100644
--- a/test/AElf.Contracts.Configuration.Tests/ConfigurationContractTest.cs
+++ b/test/AElf.Contracts.Configuration.Tests/ConfigurationContractTest.cs
@@ -345,13 +345,15 @@ public async Task SetMethodFee_Failed_Test()
// token is not profitable
{
var tokenSymbol = "DLS";
+ await CreateTokenAsync(tokenSymbol);
await Tester.ExecuteContractWithMiningAsync(TokenContractAddress,
nameof(TokenContractContainer.TokenContractStub.Create), new CreateInput
{
Symbol = tokenSymbol,
TokenName = "name",
Issuer = TokenContractAddress,
- TotalSupply = 1000_000
+ TotalSupply = 1000_000,
+ Owner = TokenContractAddress
});
var result = await Tester.ExecuteContractWithMiningAsync(ConfigurationContractAddress,
diff --git a/test/AElf.Contracts.Configuration.Tests/ConfigurationContractTestBase.cs b/test/AElf.Contracts.Configuration.Tests/ConfigurationContractTestBase.cs
index aa42ed0d40..e15bd44ad2 100644
--- a/test/AElf.Contracts.Configuration.Tests/ConfigurationContractTestBase.cs
+++ b/test/AElf.Contracts.Configuration.Tests/ConfigurationContractTestBase.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using AElf.Contracts.Configuration;
+using AElf.Contracts.MultiToken;
using AElf.Contracts.Parliament;
using AElf.Contracts.TestBase;
using AElf.Cryptography.ECDSA;
@@ -168,4 +169,52 @@ protected async Task GetMethodFeeController(Address configuration
new Empty());
return AuthorityInfo.Parser.ParseFrom(methodFeeControllerByteString);
}
+
+ protected async Task CreateTokenAsync(string symbol)
+ {
+ await Tester.ExecuteContractWithMiningAsync(TokenContractAddress,
+ nameof(TokenContractContainer.TokenContractStub.Create),
+ new CreateInput
+ {
+ Symbol = "SEED-0",
+ Decimals = 0,
+ IsBurnable = true,
+ TokenName = "seed Collection",
+ TotalSupply = 1,
+ Issuer = Tester.GetCallOwnerAddress(),
+ ExternalInfo = new ExternalInfo(),
+ Owner = Tester.GetCallOwnerAddress()
+ });
+ await Tester.ExecuteContractWithMiningAsync(TokenContractAddress,
+ nameof(TokenContractContainer.TokenContractStub.Create),
+ new CreateInput
+ {
+ Symbol = "SEED-1",
+ Decimals = 0,
+ IsBurnable = true,
+ TokenName = "seed",
+ TotalSupply = 1,
+ Issuer = Tester.GetCallOwnerAddress(),
+ ExternalInfo = new ExternalInfo
+ {
+ Value =
+ {
+ { "__seed_owned_symbol", symbol },
+ { "__seed_exp_time", TimestampHelper.GetUtcNow().AddDays(1).Seconds.ToString() }
+ }
+ },
+ LockWhiteList = { TokenContractAddress },
+ Owner = Tester.GetCallOwnerAddress()
+ });
+
+ await Tester.ExecuteContractWithMiningAsync(TokenContractAddress,
+ nameof(TokenContractContainer.TokenContractStub.Issue),
+ new IssueInput
+ {
+ Symbol = "SEED-1",
+ Amount = 1,
+ To = Tester.GetCallOwnerAddress(),
+ Memo = "test"
+ });
+ }
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.Consensus.AEDPoS.Tests/AEDPoSContractTestBase.cs b/test/AElf.Contracts.Consensus.AEDPoS.Tests/AEDPoSContractTestBase.cs
index 6cc536f844..161e9ae5ba 100644
--- a/test/AElf.Contracts.Consensus.AEDPoS.Tests/AEDPoSContractTestBase.cs
+++ b/test/AElf.Contracts.Consensus.AEDPoS.Tests/AEDPoSContractTestBase.cs
@@ -153,8 +153,9 @@ protected async Task BootMinerChangeRoundAsync(long nextRoundNumber = 2)
.AddMilliseconds(
((long)currentRound.TotalMilliseconds(AEDPoSContractTestConstants.MiningInterval)).Mul(
nextRoundNumber.Sub(1)));
+ var randomNumber = await GenerateRandomProofAsync(BootMinerKeyPair);
currentRound.GenerateNextRoundInformation(expectedStartTime.ToTimestamp(), BlockchainStartTimestamp,
- out var nextRound);
+ ByteString.CopyFrom(randomNumber), out var nextRound);
await AEDPoSContractStub.NextRound.SendAsync(nextRound);
}
@@ -167,7 +168,7 @@ protected async Task CreateProposalAsync(Address contractAddress, Address
ContractMethodName = methodName,
ExpiredTime = TimestampHelper.GetUtcNow().AddHours(1),
Params = input.ToByteString(),
- ToAddress = ConsensusContractAddress
+ ToAddress = contractAddress
};
var createResult = await ParliamentContractStub.CreateProposal.SendAsync(proposal);
diff --git a/test/AElf.Contracts.Consensus.AEDPoS.Tests/AElf.Contracts.Consensus.AEDPoS.Tests.csproj b/test/AElf.Contracts.Consensus.AEDPoS.Tests/AElf.Contracts.Consensus.AEDPoS.Tests.csproj
index 0a1b7fb34b..f9397a21b3 100644
--- a/test/AElf.Contracts.Consensus.AEDPoS.Tests/AElf.Contracts.Consensus.AEDPoS.Tests.csproj
+++ b/test/AElf.Contracts.Consensus.AEDPoS.Tests/AElf.Contracts.Consensus.AEDPoS.Tests.csproj
@@ -17,7 +17,7 @@
runtime; build; native; contentfiles; analyzers
-
+
all
@@ -29,10 +29,10 @@
-
-
-
-
+
+
+
+
false
Contract
@@ -43,7 +43,12 @@
Contract
PreserveNewest
-
+
+ false
+ Contract
+ PreserveNewest
+
+
@@ -116,5 +121,5 @@
-
+
diff --git a/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ACS10ImplTest.cs b/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ACS10ImplTest.cs
index 17d18c9803..80a823f031 100644
--- a/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ACS10ImplTest.cs
+++ b/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ACS10ImplTest.cs
@@ -2,6 +2,7 @@
using AElf.Contracts.MultiToken;
using AElf.Standards.ACS10;
using AElf.Types;
+using Google.Protobuf.WellKnownTypes;
using Shouldly;
using Xunit;
@@ -14,14 +15,9 @@ public async Task Consensus_Donate_With_Invalid_Token_Test()
{
var tokenSymbol = "SEP";
+ await CreateTokenAsync(tokenSymbol);
+
// Donate with token which is not profitable will fail
- await TokenContractStub.Create.SendAsync(new CreateInput
- {
- Symbol = tokenSymbol,
- TokenName = "name",
- TotalSupply = 1000_000_000,
- Issuer = BootMinerAddress
- });
var issueAmount = 1000_000;
await TokenContractStub.Issue.SendAsync(new IssueInput
{
@@ -48,4 +44,23 @@ await TokenContractStub.Issue.SendAsync(new IssueInput
});
balanceAfterDonate.Balance.ShouldBe(issueAmount);
}
+
+ private async Task CreateTokenAsync(string symbol)
+ {
+ var defaultOrganization = await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
+
+ const string proposalCreationMethodName = nameof(TokenContractStub.Create);
+ var proposalId = await CreateProposalAsync(TokenContractAddress, defaultOrganization,
+ proposalCreationMethodName, new CreateInput
+ {
+ Symbol = symbol,
+ TokenName = "name",
+ TotalSupply = 1000_000_000,
+ Issuer = BootMinerAddress,
+ Owner = BootMinerAddress
+ });
+ await ApproveWithMinersAsync(proposalId);
+ var result = await ParliamentContractStub.Release.SendAsync(proposalId);
+ var t = "t";
+ }
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ACS1ImplTest.cs b/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ACS1ImplTest.cs
index 058f3afcd9..489f4d80ad 100644
--- a/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ACS1ImplTest.cs
+++ b/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ACS1ImplTest.cs
@@ -31,7 +31,7 @@ await ParliamentContractStub.CreateOrganization.SendAsync(
const string proposalCreationMethodName =
nameof(AEDPoSContractImplContainer.AEDPoSContractImplStub.ChangeMethodFeeController);
- var proposalId = await CreateProposalAsync(methodFeeController.ContractAddress,
+ var proposalId = await CreateProposalAsync(ConsensusContractAddress,
methodFeeController.OwnerAddress, proposalCreationMethodName, new AuthorityInfo
{
OwnerAddress = organizationAddress,
diff --git a/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ACS4ImplTest.cs b/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ACS4ImplTest.cs
index f567de3d69..8e1d56ce9c 100644
--- a/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ACS4ImplTest.cs
+++ b/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ACS4ImplTest.cs
@@ -1,6 +1,7 @@
using System.Linq;
using System.Threading.Tasks;
using AElf.CSharp.Core;
+using AElf.Kernel;
using AElf.Standards.ACS4;
using AElf.TestBase;
using AElf.Types;
@@ -74,10 +75,12 @@ private async Task AEDPoSContract_GenerateConsensusTransactions
});
var triggerForCommand =
- TriggerInformationProvider.GetTriggerInformationForConsensusTransactions(
+ TriggerInformationProvider.GetTriggerInformationForConsensusTransactions(new ChainContext(),
consensusCommand.ToBytesValue());
+ var trigger = AElfConsensusTriggerInformation.Parser.ParseFrom(triggerForCommand.Value);
+ trigger.RandomNumber = ByteString.CopyFrom(await GenerateRandomProofAsync(BootMinerKeyPair));
- var transactionList = await AEDPoSContractStub.GenerateConsensusTransactions.CallAsync(triggerForCommand);
+ var transactionList = await AEDPoSContractStub.GenerateConsensusTransactions.CallAsync(trigger.ToBytesValue());
transactionList.Transactions.Count.ShouldBe(1);
transactionList.Transactions[0].MethodName.ShouldBe(nameof(AEDPoSContractStub.UpdateValue));
@@ -175,9 +178,11 @@ private async Task AEDPoSContract_GenerateConsensusTransactions
});
var triggerForCommand = TriggerInformationProvider
- .GetTriggerInformationForConsensusTransactions(consensusCommand.ToBytesValue());
+ .GetTriggerInformationForConsensusTransactions(new ChainContext(), consensusCommand.ToBytesValue());
+ var trigger = AElfConsensusTriggerInformation.Parser.ParseFrom(triggerForCommand.Value);
+ trigger.RandomNumber = ByteString.CopyFrom(await GenerateRandomProofAsync(usingKeyPair));
- var transactionList = await AEDPoSContractStub.GenerateConsensusTransactions.CallAsync(triggerForCommand);
+ var transactionList = await AEDPoSContractStub.GenerateConsensusTransactions.CallAsync(trigger.ToBytesValue());
transactionList.Transactions.Count.ShouldBe(1);
transactionList.Transactions[0].MethodName.ShouldBe(nameof(AEDPoSContractStub.UpdateValue));
@@ -252,8 +257,10 @@ public async Task AEDPoSContract_GetInformationToUpdateConsensus_FirstRound_Extr
var triggerForCommand = TriggerInformationProvider
.GetTriggerInformationForBlockHeaderExtraData(consensusCommand.ToBytesValue());
+ var trigger = AElfConsensusTriggerInformation.Parser.ParseFrom(triggerForCommand.Value);
+ trigger.RandomNumber = ByteString.CopyFrom(await GenerateRandomProofAsync(usingKeyPair));
- var extraDataBytes = await AEDPoSContractStub.GetConsensusExtraData.CallAsync(triggerForCommand);
+ var extraDataBytes = await AEDPoSContractStub.GetConsensusExtraData.CallAsync(trigger.ToBytesValue());
var extraData = extraDataBytes.ToConsensusHeaderInformation();
@@ -275,9 +282,11 @@ private async Task
});
var triggerForCommand = TriggerInformationProvider
- .GetTriggerInformationForConsensusTransactions(consensusCommand.ToBytesValue());
-
- var transactionList = await AEDPoSContractStub.GenerateConsensusTransactions.CallAsync(triggerForCommand);
+ .GetTriggerInformationForConsensusTransactions(new ChainContext(), consensusCommand.ToBytesValue());
+ var trigger = AElfConsensusTriggerInformation.Parser.ParseFrom(triggerForCommand.Value);
+ trigger.RandomNumber = ByteString.CopyFrom(await GenerateRandomProofAsync(usingKeyPair));
+
+ var transactionList = await AEDPoSContractStub.GenerateConsensusTransactions.CallAsync(trigger.ToBytesValue());
transactionList.Transactions.Count.ShouldBe(1);
transactionList.Transactions[0].MethodName.ShouldBe(nameof(AEDPoSContractStub.NextRound));
@@ -298,7 +307,7 @@ public async Task AEDPoSContract_FirstRound_Terminate_Test()
.Div(1000)
});
- var nextRound = new Round();
+ var nextRound = new NextRoundInput();
nextRound.MergeFrom(transaction.Params);
await AEDPoSContractStub.NextRound.SendAsync(nextRound);
@@ -323,10 +332,13 @@ public async Task AEDPoSContract_ConsensusTransactionValidation_Test()
validateBeforeResult.Success.ShouldBeTrue();
var roundInfo = await AEDPoSContractStub.GetCurrentRoundInformation.CallAsync(new Empty());
- roundInfo.RoundNumber++;
- roundInfo.IsMinerListJustChanged = false;
- roundInfo.TermNumber++;
- var transactionResult = await AEDPoSContractStub.NextRound.SendAsync(roundInfo);
+ var nextRoundInput = NextRoundInput.Parser.ParseFrom(roundInfo.ToByteArray());
+ nextRoundInput.RoundNumber++;
+ nextRoundInput.IsMinerListJustChanged = false;
+ nextRoundInput.TermNumber++;
+ var randomNumber = await GenerateRandomProofAsync(BootMinerKeyPair);
+ nextRoundInput.RandomNumber = ByteString.CopyFrom(randomNumber);
+ var transactionResult = await AEDPoSContractStub.NextRound.SendAsync(nextRoundInput);
transactionResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
var validateAfterResult =
@@ -402,10 +414,12 @@ public async Task AEDPoSContract_GenerateConsensusTransaction_TinyBlock_Test()
});
var triggerForCommand = TriggerInformationProvider
- .GetTriggerInformationForConsensusTransactions(consensusCommand.ToBytesValue());
+ .GetTriggerInformationForConsensusTransactions(new ChainContext(), consensusCommand.ToBytesValue());
+ var trigger = AElfConsensusTriggerInformation.Parser.ParseFrom(triggerForCommand.Value);
+ trigger.RandomNumber = ByteString.CopyFrom(await GenerateRandomProofAsync(usingKeyPair));
var transactionList =
- await AEDPoSContractStub.GenerateConsensusTransactions.CallAsync(triggerForCommand);
+ await AEDPoSContractStub.GenerateConsensusTransactions.CallAsync(trigger.ToBytesValue());
transactionList.Transactions.Count.ShouldBe(1);
transactionList.Transactions[0].MethodName
@@ -433,10 +447,12 @@ public async Task AEDPoSContract_GenerateConsensusTransaction_NextTerm_Test()
});
var triggerForCommand = TriggerInformationProvider
- .GetTriggerInformationForConsensusTransactions(consensusCommand.ToBytesValue());
+ .GetTriggerInformationForConsensusTransactions(new ChainContext(), consensusCommand.ToBytesValue());
+ var trigger = AElfConsensusTriggerInformation.Parser.ParseFrom(triggerForCommand.Value);
+ trigger.RandomNumber = ByteString.CopyFrom(await GenerateRandomProofAsync(usingKeyPair));
var transactionList =
- await AEDPoSContractStub.GenerateConsensusTransactions.CallAsync(triggerForCommand);
+ await AEDPoSContractStub.GenerateConsensusTransactions.CallAsync(trigger.ToBytesValue());
transactionList.Transactions.Count.ShouldBe(1);
transactionList.Transactions[0].MethodName.ShouldBe(nameof(AEDPoSContractStub.NextTerm));
diff --git a/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/MinersCountTest.cs b/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/MinersCountTest.cs
index bbc2310b9f..f053759f68 100644
--- a/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/MinersCountTest.cs
+++ b/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/MinersCountTest.cs
@@ -52,6 +52,7 @@ public async Task AEDPoSContract_ChangeMinersCount_Test()
voteResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
}
+ byte[] randomNumber;
foreach (var minerInRound in firstRound.RealTimeMinersInformation.Values.OrderBy(m => m.Order))
{
var currentKeyPair = InitialCoreDataCenterKeyPairs.First(p => p.PublicKey.ToHex() == minerInRound.Pubkey);
@@ -65,8 +66,11 @@ public async Task AEDPoSContract_ChangeMinersCount_Test()
(await AEDPoSContractStub.GetConsensusExtraData.CallAsync(triggers[minerInRound.Pubkey]
.ToBytesValue())).ToConsensusHeaderInformation();
+ randomNumber = await GenerateRandomProofAsync(currentKeyPair);
// Update consensus information.
- var toUpdate = headerInformation.Round.ExtractInformationToUpdateConsensus(minerInRound.Pubkey);
+ var toUpdate =
+ headerInformation.Round.ExtractInformationToUpdateConsensus(minerInRound.Pubkey,
+ ByteString.CopyFrom(randomNumber));
await tester.UpdateValue.SendAsync(toUpdate);
}
@@ -80,7 +84,10 @@ public async Task AEDPoSContract_ChangeMinersCount_Test()
Pubkey = ByteString.CopyFrom(BootMinerKeyPair.PublicKey)
}.ToBytesValue())).ToConsensusHeaderInformation();
- await AEDPoSContractStub.NextRound.SendAsync(nextTermInformation.Round);
+ var nextRoundInput = NextRoundInput.Parser.ParseFrom(nextTermInformation.Round.ToByteArray());
+ randomNumber = await GenerateRandomProofAsync(BootMinerKeyPair);
+ nextRoundInput.RandomNumber = ByteString.CopyFrom(randomNumber);
+ await AEDPoSContractStub.NextRound.SendAsync(nextRoundInput);
changeTermTime = BlockchainStartTimestamp.ToDateTime().AddMinutes(termIntervalMin).AddSeconds(10);
BlockTimeProvider.SetBlockTime(changeTermTime.ToTimestamp());
@@ -91,7 +98,10 @@ public async Task AEDPoSContract_ChangeMinersCount_Test()
Pubkey = ByteString.CopyFrom(BootMinerKeyPair.PublicKey)
}.ToBytesValue())).ToConsensusHeaderInformation();
- var transactionResult = await AEDPoSContractStub.NextTerm.SendAsync(nextTermInformation.Round);
+ var nextTermInput = NextTermInput.Parser.ParseFrom(nextTermInformation.Round.ToByteArray());
+ randomNumber = await GenerateRandomProofAsync(BootMinerKeyPair);
+ nextTermInput.RandomNumber = ByteString.CopyFrom(randomNumber);
+ var transactionResult = await AEDPoSContractStub.NextTerm.SendAsync(nextTermInput);
transactionResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
var newMinerStub = GetAEDPoSContractStub(ValidationDataCenterKeyPairs[0]);
@@ -101,8 +111,8 @@ public async Task AEDPoSContract_ChangeMinersCount_Test()
{
var currentRound = await newMinerStub.GetCurrentRoundInformation.CallAsync(new Empty());
var firstPubKey = currentRound.RealTimeMinersInformation.Keys.First();
- newMinerStub =
- GetAEDPoSContractStub(ValidationDataCenterKeyPairs.First(o => o.PublicKey.ToHex() == firstPubKey));
+ var keypair = ValidationDataCenterKeyPairs.First(o => o.PublicKey.ToHex() == firstPubKey);
+ newMinerStub = GetAEDPoSContractStub(keypair);
minerCount = currentRound.RealTimeMinersInformation.Count;
Assert.Equal(AEDPoSContractTestConstants.SupposedMinersCount.Add(termCount.Mul(2)), minerCount);
@@ -117,8 +127,10 @@ public async Task AEDPoSContract_ChangeMinersCount_Test()
Pubkey = ByteStringHelper.FromHexString(currentRound.RealTimeMinersInformation.ElementAt(0).Value
.Pubkey)
}.ToBytesValue())).ToConsensusHeaderInformation();
-
- await newMinerStub.NextTerm.SendAsync(nextRoundInformation.Round);
+ nextTermInput = NextTermInput.Parser.ParseFrom(nextRoundInformation.Round.ToByteArray());
+ randomNumber = await GenerateRandomProofAsync(keypair);
+ nextTermInput.RandomNumber = ByteString.CopyFrom(randomNumber);
+ await newMinerStub.NextTerm.SendAsync(nextTermInput);
termCount++;
}
}
diff --git a/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/MiningProcessTest.cs b/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/MiningProcessTest.cs
index cb9dfcf1ff..43570af8f2 100644
--- a/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/MiningProcessTest.cs
+++ b/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/MiningProcessTest.cs
@@ -44,6 +44,8 @@ await voter.Vote.SendAsync(new VoteMinerInput
EndTimestamp = TimestampHelper.GetUtcNow().AddDays(100)
});
+ var randomHash = Hash.Empty.ToByteArray();
+ byte[] randomNumber;
foreach (var minerInRound in firstRound.RealTimeMinersInformation.Values.OrderBy(m => m.Order))
{
var currentKeyPair =
@@ -57,9 +59,9 @@ await voter.Vote.SendAsync(new VoteMinerInput
var headerInformation =
(await AEDPoSContractStub.GetConsensusExtraData.CallAsync(triggers[minerInRound.Pubkey]
.ToBytesValue())).ToConsensusHeaderInformation();
-
+ randomNumber = await GenerateRandomProofAsync(currentKeyPair);
// Update consensus information.
- var toUpdate = headerInformation.Round.ExtractInformationToUpdateConsensus(minerInRound.Pubkey);
+ var toUpdate = headerInformation.Round.ExtractInformationToUpdateConsensus(minerInRound.Pubkey, ByteString.CopyFrom(randomNumber));
await tester.UpdateValue.SendAsync(toUpdate);
}
@@ -73,24 +75,27 @@ await voter.Vote.SendAsync(new VoteMinerInput
Behaviour = AElfConsensusBehaviour.NextTerm,
Pubkey = ByteString.CopyFrom(BootMinerKeyPair.PublicKey)
}.ToBytesValue())).ToConsensusHeaderInformation();
-
- await AEDPoSContractStub.NextTerm.SendAsync(nextTermInformation.Round);
+ var nextTermInput = NextTermInput.Parser.ParseFrom(nextTermInformation.Round.ToByteArray());
+ randomNumber = await GenerateRandomProofAsync(BootMinerKeyPair);
+ nextTermInput.RandomNumber = ByteString.CopyFrom(randomNumber);
+ await AEDPoSContractStub.NextTerm.SendAsync(nextTermInput);
// First candidate cheat others with in value.
var oneCandidate = GetAEDPoSContractStub(ValidationDataCenterKeyPairs[0]);
var anotherCandidate = GetAEDPoSContractStub(ValidationDataCenterKeyPairs[1]);
- var randomHash = HashHelper.ComputeFrom("hash5");
+ var inValue = HashHelper.ComputeFrom("hash5");
var informationOfSecondRound = (await AEDPoSContractStub.GetConsensusExtraData.CallAsync(
new AElfConsensusTriggerInformation
{
Behaviour = AElfConsensusBehaviour.UpdateValue,
PreviousInValue = Hash.Empty,
- InValue = randomHash,
+ InValue = inValue,
Pubkey = ByteString.CopyFrom(ValidationDataCenterKeyPairs[0].PublicKey)
}.ToBytesValue())).ToConsensusHeaderInformation();
+ randomNumber = await GenerateRandomProofAsync(ValidationDataCenterKeyPairs[0]);
var updateResult = await oneCandidate.UpdateValue.SendAsync(
informationOfSecondRound.Round.ExtractInformationToUpdateConsensus(ValidationDataCenterKeyPairs[0]
- .PublicKey.ToHex()));
+ .PublicKey.ToHex(), ByteString.CopyFrom(randomNumber)));
var thirdRoundStartTime = changeTermTime.AddMinutes(AEDPoSContractTestConstants.PeriodSeconds + 2);
BlockTimeProvider.SetBlockTime(thirdRoundStartTime.ToTimestamp());
@@ -100,20 +105,23 @@ await voter.Vote.SendAsync(new VoteMinerInput
Behaviour = AElfConsensusBehaviour.NextRound,
Pubkey = ByteString.CopyFrom(ValidationDataCenterKeyPairs[0].PublicKey)
}.ToBytesValue())).ToConsensusHeaderInformation().Round;
-
- await oneCandidate.NextRound.SendAsync(thirdRound);
+ var nextRoundInput = NextRoundInput.Parser.ParseFrom(thirdRound.ToByteArray());
+ randomNumber = await GenerateRandomProofAsync(ValidationDataCenterKeyPairs[0]);
+ nextRoundInput.RandomNumber = ByteString.CopyFrom(randomNumber);
+ await oneCandidate.NextRound.SendAsync(nextRoundInput);
var cheatInformation = (await AEDPoSContractStub.GetConsensusExtraData.CallAsync(
new AElfConsensusTriggerInformation
{
Behaviour = AElfConsensusBehaviour.UpdateValue,
- PreviousInValue = HashHelper.ComputeFrom(randomHash), // Not same as before.
+ PreviousInValue = HashHelper.ComputeFrom(inValue), // Not same as before.
InValue = HashHelper.ComputeFrom("InValue"), // Don't care this value in current test case.
Pubkey = ByteString.CopyFrom(ValidationDataCenterKeyPairs[0].PublicKey)
}.ToBytesValue())).ToConsensusHeaderInformation();
+ randomNumber = await GenerateRandomProofAsync(ValidationDataCenterKeyPairs[0]);
await oneCandidate.UpdateValue.SendAsync(
cheatInformation.Round.ExtractInformationToUpdateConsensus(ValidationDataCenterKeyPairs[0].PublicKey
- .ToHex()));
+ .ToHex(), ByteString.CopyFrom(randomNumber)));
}
[Fact]
@@ -131,7 +139,8 @@ public async Task Update_TinyBlockInformation_Test()
{
RoundId = roundInfo.RoundId,
ProducedBlocks = 4,
- ActualMiningTime = BlockTimeProvider.GetBlockTime()
+ ActualMiningTime = BlockTimeProvider.GetBlockTime(),
+ RandomNumber = ByteString.CopyFrom(await GenerateRandomProofAsync(BootMinerKeyPair))
};
var transactionResult = await AEDPoSContractStub.UpdateTinyBlockInformation.SendAsync(input);
transactionResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
diff --git a/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ViewTests.cs b/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ViewTests.cs
index b75b324ccf..d23ca5613a 100644
--- a/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ViewTests.cs
+++ b/test/AElf.Contracts.Consensus.AEDPoS.Tests/BVT/ViewTests.cs
@@ -1,5 +1,6 @@
using System.Linq;
using System.Threading.Tasks;
+using AElf.Cryptography;
using AElf.Types;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
@@ -27,7 +28,10 @@ public async Task Query_RoundInformation_Test()
Pubkey = ByteString.CopyFrom(BootMinerKeyPair.PublicKey)
}.ToBytesValue())).ToConsensusHeaderInformation();
- var transactionResult = await AEDPoSContractStub.NextRound.SendAsync(nextTermInformation.Round);
+ var nextRoundInput = NextRoundInput.Parser.ParseFrom(nextTermInformation.Round.ToByteArray());
+ var randomNumber = await GenerateRandomProofAsync(BootMinerKeyPair);
+ nextRoundInput.RandomNumber = ByteString.CopyFrom(randomNumber);
+ var transactionResult = await AEDPoSContractStub.NextRound.SendAsync(nextRoundInput);
transactionResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
roundNumber = await AEDPoSContractStub.GetCurrentRoundNumber.CallAsync(new Empty());
diff --git a/test/AElf.Contracts.Consensus.AEDPoS.Tests/Types/Round.cs b/test/AElf.Contracts.Consensus.AEDPoS.Tests/Types/Round.cs
index f0e6cee28e..6f6acaf2bf 100644
--- a/test/AElf.Contracts.Consensus.AEDPoS.Tests/Types/Round.cs
+++ b/test/AElf.Contracts.Consensus.AEDPoS.Tests/Types/Round.cs
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using AElf.Types;
+using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
namespace AElf.Contracts.Consensus.AEDPoS;
@@ -85,8 +86,9 @@ public int TotalMilliseconds(int miningInterval = 0)
/// will record this purpose to their FinalOrderOfNextRound field.
///
///
+ ///
///
- public UpdateValueInput ExtractInformationToUpdateConsensus(string pubkey)
+ public UpdateValueInput ExtractInformationToUpdateConsensus(string pubkey, ByteString randomNumber)
{
if (!RealTimeMinersInformation.ContainsKey(pubkey)) return null;
@@ -117,7 +119,8 @@ public UpdateValueInput ExtractInformationToUpdateConsensus(string pubkey)
TuneOrderInformation = { tuneOrderInformation },
EncryptedPieces = { minerInRound.EncryptedPieces },
DecryptedPieces = { decryptedPreviousInValues },
- MinersPreviousInValues = { minersPreviousInValues }
+ MinersPreviousInValues = { minersPreviousInValues },
+ RandomNumber = randomNumber
};
}
diff --git a/test/AElf.Contracts.Consensus.AEDPoS.Tests/Types/Round_Generation.cs b/test/AElf.Contracts.Consensus.AEDPoS.Tests/Types/Round_Generation.cs
index 34830558d0..6965e4c874 100644
--- a/test/AElf.Contracts.Consensus.AEDPoS.Tests/Types/Round_Generation.cs
+++ b/test/AElf.Contracts.Consensus.AEDPoS.Tests/Types/Round_Generation.cs
@@ -1,16 +1,18 @@
using System.Collections.Generic;
using System.Linq;
using AElf.CSharp.Core;
+using AElf.Types;
+using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
namespace AElf.Contracts.Consensus.AEDPoS;
internal partial class Round
{
- public bool GenerateNextRoundInformation(Timestamp currentBlockTimestamp, Timestamp blockchainStartTimestamp,
- out Round nextRound)
+ public bool GenerateNextRoundInformation(Timestamp currentBlockTimestamp, Timestamp blockchainStartTimestamp, ByteString randomNumber,
+ out NextRoundInput nextRound)
{
- nextRound = new Round();
+ nextRound = new NextRoundInput();
var minersMinedCurrentRound = GetMinedMiners();
var minersNotMinedCurrentRound = GetNotMinedMiners();
@@ -65,7 +67,8 @@ public bool GenerateNextRoundInformation(Timestamp currentBlockTimestamp, Timest
nextRound.RealTimeMinersInformation.Values.First().IsExtraBlockProducer = true;
else
expectedExtraBlockProducer.IsExtraBlockProducer = true;
-
+ nextRound.RandomNumber = randomNumber;
+
return true;
}
diff --git a/test/AElf.Contracts.CrossChain.Tests/CrossChainContractTestBase.cs b/test/AElf.Contracts.CrossChain.Tests/CrossChainContractTestBase.cs
index 11e08408eb..dd09f11b48 100644
--- a/test/AElf.Contracts.CrossChain.Tests/CrossChainContractTestBase.cs
+++ b/test/AElf.Contracts.CrossChain.Tests/CrossChainContractTestBase.cs
@@ -160,17 +160,25 @@ private async Task InitializeTokenAsync()
{
const string symbol = "ELF";
const long totalSupply = 100_000_000;
- await MineAsync(new List
- {
- TokenContractStub.Create.GetTransaction(new CreateInput
+
+ var parliamentOrganizationAddress =
+ (await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty()));
+ var approveProposalId = await CreateParliamentProposalAsync(nameof(TokenContractStub.Create),
+ parliamentOrganizationAddress, new CreateInput
{
Symbol = symbol,
Decimals = 2,
IsBurnable = true,
TokenName = "elf token",
TotalSupply = totalSupply,
- Issuer = DefaultSender
- }),
+ Issuer = DefaultSender,
+ Owner = DefaultSender
+ }, TokenContractAddress);
+ await ApproveWithMinersAsync(approveProposalId);
+ await ParliamentContractStub.Release.SendAsync(approveProposalId);
+
+ await MineAsync(new List
+ {
TokenContractStub.Issue.GetTransaction(new IssueInput
{
Symbol = symbol,
diff --git a/test/AElf.Contracts.Economic.TestBase/AElf.Contracts.Economic.TestBase.csproj b/test/AElf.Contracts.Economic.TestBase/AElf.Contracts.Economic.TestBase.csproj
index 95287fb207..c0b204fe14 100644
--- a/test/AElf.Contracts.Economic.TestBase/AElf.Contracts.Economic.TestBase.csproj
+++ b/test/AElf.Contracts.Economic.TestBase/AElf.Contracts.Economic.TestBase.csproj
@@ -13,16 +13,16 @@
runtime; build; native; contentfiles; analyzers
-
+
- all
- runtime; build; native; contentfiles; analyzers
-
+ all
+ runtime; build; native; contentfiles; analyzers
+
- all
- runtime; build; native; contentfiles; analyzers
-
+ all
+ runtime; build; native; contentfiles; analyzers
+
@@ -71,9 +71,9 @@
Contract
PreserveNewest
-
-
-
+
+
+
false
Contract
@@ -99,8 +99,13 @@
Contract
PreserveNewest
-
-
+
+ false
+ Contract
+ PreserveNewest
+
+
+
@@ -179,8 +184,11 @@
Protobuf\Proto\parliament_contract_impl.proto
+
+ Protobuf\Proto\test_virtual_address_contract.proto
+
-
+
diff --git a/test/AElf.Contracts.Economic.TestBase/Contracts.cs b/test/AElf.Contracts.Economic.TestBase/Contracts.cs
index 3e32bdd1cd..2bd259d94a 100644
--- a/test/AElf.Contracts.Economic.TestBase/Contracts.cs
+++ b/test/AElf.Contracts.Economic.TestBase/Contracts.cs
@@ -26,7 +26,8 @@ public enum TestContracts
BasicSecurity,
BasicUpdate,
MethodCallThreshold,
- ResourceSpender
+ ResourceSpender,
+ VirtualAddress
}
public enum ProfitType
diff --git a/test/AElf.Contracts.Economic.TestBase/ContractsPreparation.cs b/test/AElf.Contracts.Economic.TestBase/ContractsPreparation.cs
index 04437a46a8..cde20e76c9 100644
--- a/test/AElf.Contracts.Economic.TestBase/ContractsPreparation.cs
+++ b/test/AElf.Contracts.Economic.TestBase/ContractsPreparation.cs
@@ -10,6 +10,7 @@
using AElf.Contracts.Parliament;
using AElf.Contracts.Profit;
using AElf.Contracts.TestContract.MethodCallThreshold;
+using AElf.Contracts.TestContract.VirtualAddress;
using AElf.Contracts.TestContract.TransactionFeeCharging;
using AElf.Contracts.TokenConverter;
using AElf.Contracts.Treasury;
@@ -102,6 +103,9 @@ public partial class EconomicContractsTestBase
protected Address ConfigurationAddress =>
GetOrDeployContract(Contracts.Configuration, ref _configurationAddress);
+
+ private Address _virtualAddressContractAddress;
+ protected Address VirtualAddressContractAddress => GetOrDeployContract(TestContracts.VirtualAddress, ref _virtualAddressContractAddress);
#endregion
@@ -144,6 +148,9 @@ internal TransactionFeeChargingContractContainer.TransactionFeeChargingContractS
internal ConfigurationContainer.ConfigurationStub ConfigurationStub =>
GetConfigurationContractTester(BootMinerKeyPair);
+
+ internal VirtualAddressContractContainer.VirtualAddressContractStub VirtualAddressContractStub =>
+ GetVirtualAddressContractTester(BootMinerKeyPair);
#endregion
@@ -223,6 +230,11 @@ internal ConfigurationContainer.ConfigurationStub GetConfigurationContractTester
{
return GetTester(ConfigurationAddress, keyPair);
}
+
+ internal VirtualAddressContractContainer.VirtualAddressContractStub GetVirtualAddressContractTester(ECKeyPair keyPair)
+ {
+ return GetTester(VirtualAddressContractAddress, keyPair);
+ }
#endregion
@@ -308,6 +320,7 @@ protected void DeployAllContracts()
_ = TokenContractAddress;
_ = TokenHolderContractAddress;
_ = AssociationContractAddress;
+ _ = VirtualAddressContractAddress;
}
#endregion
@@ -500,7 +513,7 @@ protected async Task InitializeAElfConsensus()
new MinerList
{
Pubkeys = { InitialCoreDataCenterKeyPairs.Select(p => ByteString.CopyFrom(p.PublicKey)) }
- }.GenerateFirstRoundOfNewTerm(EconomicContractsTestConstants.MiningInterval, StartTimestamp));
+ }.GenerateFirstRound(EconomicContractsTestConstants.MiningInterval, StartTimestamp));
CheckResult(result.TransactionResult);
}
}
@@ -509,12 +522,35 @@ protected async Task InitializeTransactionFeeChargingContract()
{
await ExecuteProposalForParliamentTransaction(TokenContractAddress,
nameof(TokenContractStub.AddAddressToCreateTokenWhiteList), TransactionFeeChargingContractAddress);
- var result = await TransactionFeeChargingContractStub.InitializeTransactionFeeChargingContract.SendAsync(
- new InitializeTransactionFeeChargingContractInput
+
+ await ExecuteProposalForParliamentTransaction(TokenContractAddress, nameof(TokenContractStub.Create), new CreateInput
+ {
+ Symbol = EconomicContractsTestConstants.TransactionFeeChargingContractTokenSymbol,
+ TokenName = "Token of Transaction Fee Charging Contract",
+ Decimals = 2,
+ Issuer = BootMinerAddress,
+ IsBurnable = true,
+ TotalSupply = 1_000_000_000,
+ LockWhiteList =
{
- Symbol = EconomicContractsTestConstants.TransactionFeeChargingContractTokenSymbol
- });
- CheckResult(result.TransactionResult);
+ TokenConverterContractAddress,
+ TreasuryContractAddress
+ },
+ Owner = BootMinerAddress
+ });
+ await TokenContractStub.Issue.SendAsync(new IssueInput
+ {
+ Symbol = EconomicContractsTestConstants.TransactionFeeChargingContractTokenSymbol,
+ Amount = 100_000,
+ To = TokenConverterContractAddress
+ });
+
+ // var result = await TransactionFeeChargingContractStub.InitializeTransactionFeeChargingContract.SendAsync(
+ // new InitializeTransactionFeeChargingContractInput
+ // {
+ // Symbol = EconomicContractsTestConstants.TransactionFeeChargingContractTokenSymbol
+ // });
+ // CheckResult(result.TransactionResult);
{
var approveResult = await TokenContractStub.Approve.SendAsync(new ApproveInput
diff --git a/test/AElf.Contracts.Economic.TestBase/EconomicContractsTestBase.cs b/test/AElf.Contracts.Economic.TestBase/EconomicContractsTestBase.cs
index 60a5a0d350..b4f5419397 100644
--- a/test/AElf.Contracts.Economic.TestBase/EconomicContractsTestBase.cs
+++ b/test/AElf.Contracts.Economic.TestBase/EconomicContractsTestBase.cs
@@ -3,6 +3,7 @@
using AElf.ContractTestKit;
using AElf.Cryptography.ECDSA;
using AElf.Kernel;
+using AElf.Kernel.Blockchain.Application;
using AElf.Types;
using Google.Protobuf.WellKnownTypes;
using Microsoft.Extensions.DependencyInjection;
@@ -13,6 +14,9 @@ public partial class EconomicContractsTestBase : ContractTestBase
Application.ServiceProvider.GetRequiredService();
+
+ protected IBlockchainService BlockchainService =>
+ Application.ServiceProvider.GetRequiredService();
protected Timestamp StartTimestamp => TimestampHelper.GetUtcNow();
diff --git a/test/AElf.Contracts.Economic.TestBase/EconomicContractsTestModule.cs b/test/AElf.Contracts.Economic.TestBase/EconomicContractsTestModule.cs
index 158133ef8a..6d50eeb482 100644
--- a/test/AElf.Contracts.Economic.TestBase/EconomicContractsTestModule.cs
+++ b/test/AElf.Contracts.Economic.TestBase/EconomicContractsTestModule.cs
@@ -26,6 +26,7 @@ public override void ConfigureServices(ServiceConfigurationContext context)
// context.Services.AddSingleton();
context.Services.AddSingleton();
context.Services.AddSingleton();
+ context.Services.AddTransient();
context.Services.RemoveAll();
}
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.Economic.TestBase/MockRandomNumberProvider.cs b/test/AElf.Contracts.Economic.TestBase/MockRandomNumberProvider.cs
new file mode 100644
index 0000000000..8bcd0d3d61
--- /dev/null
+++ b/test/AElf.Contracts.Economic.TestBase/MockRandomNumberProvider.cs
@@ -0,0 +1,22 @@
+using System.Threading.Tasks;
+using AElf.Kernel;
+using AElf.Kernel.Account.Application;
+using AElf.Kernel.Consensus.AEDPoS.Application;
+using AElf.Types;
+
+namespace AElf.Contracts.Economic.TestBase;
+
+public class MockRandomNumberProvider : IRandomNumberProvider
+{
+ private readonly IAccountService _accountService;
+
+ public MockRandomNumberProvider(IAccountService accountService)
+ {
+ _accountService = accountService;
+ }
+
+ public async Task GenerateRandomProofAsync(IChainContext chainContext)
+ {
+ return await _accountService.ECVrfProveAsync(Hash.Empty.ToByteArray());
+ }
+}
\ No newline at end of file
diff --git a/test/AElf.Contracts.Economic.TestBase/OtherContractsOperation.cs b/test/AElf.Contracts.Economic.TestBase/OtherContractsOperation.cs
index 76622df755..d89e73bd70 100644
--- a/test/AElf.Contracts.Economic.TestBase/OtherContractsOperation.cs
+++ b/test/AElf.Contracts.Economic.TestBase/OtherContractsOperation.cs
@@ -1,8 +1,10 @@
using System.Threading.Tasks;
using AElf.Contracts.Consensus.AEDPoS;
using AElf.Contracts.MultiToken;
+using AElf.Cryptography;
using AElf.Cryptography.ECDSA;
using AElf.Types;
+using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using Shouldly;
@@ -24,9 +26,10 @@ protected async Task NextTerm(ECKeyPair keyPair)
victories.Value
}
};
+ var randomNumber = await GenerateRandomProofAsync(keyPair);
var firstRoundOfNextTerm =
miners.GenerateFirstRoundOfNewTerm(EconomicContractsTestConstants.MiningInterval,
- BlockTimeProvider.GetBlockTime(), round.RoundNumber, round.TermNumber);
+ randomNumber, BlockTimeProvider.GetBlockTime(), round.RoundNumber, round.TermNumber);
var executionResult = (await miner.NextTerm.SendAsync(firstRoundOfNextTerm)).TransactionResult;
executionResult.Error.ShouldBeNullOrEmpty();
executionResult.Status.ShouldBe(TransactionResultStatus.Mined);
@@ -36,9 +39,10 @@ protected async Task NextRound(ECKeyPair keyPair)
{
var miner = GetConsensusContractTester(keyPair);
var round = await miner.GetCurrentRoundInformation.CallAsync(new Empty());
+ var randomNumber = await GenerateRandomProofAsync(keyPair);
round.GenerateNextRoundInformation(
StartTimestamp.ToDateTime().AddMilliseconds(round.TotalMilliseconds()).ToTimestamp(), StartTimestamp,
- out var nextRound);
+ ByteString.CopyFrom(randomNumber), out var nextRound);
await miner.NextRound.SendAsync(nextRound);
}
@@ -56,7 +60,8 @@ await miner.UpdateValue.SendAsync(new UpdateValueInput
RoundId = round.RoundId,
ProducedBlocks = minerInRound.ProducedBlocks + 1,
ActualMiningTime = minerInRound.ExpectedMiningTime,
- SupposedOrderOfNextRound = 1
+ SupposedOrderOfNextRound = 1,
+ RandomNumber = ByteString.CopyFrom(await GenerateRandomProofAsync(keyPair))
});
}
@@ -95,5 +100,17 @@ protected async Task GetVoteTokenBalance(byte[] publicKey)
return balance;
}
+ protected async Task GenerateRandomProofAsync(ECKeyPair keyPair)
+ {
+ var consensusContractStub = GetConsensusContractTester(keyPair);
+ var blockHeight = (await BlockchainService.GetChainAsync()).BestChainHeight;
+ var previousRandomHash =
+ blockHeight <= 1
+ ? Hash.Empty
+ : await consensusContractStub.GetRandomHash.CallAsync(new Int64Value
+ { Value = blockHeight });
+ return CryptoHelper.ECVrfProve(keyPair, previousRandomHash.ToByteArray());
+ }
+
#endregion
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.Economic.TestBase/Types/MinerList.cs b/test/AElf.Contracts.Economic.TestBase/Types/MinerList.cs
index ed9c3082b5..800ef0cb5a 100644
--- a/test/AElf.Contracts.Economic.TestBase/Types/MinerList.cs
+++ b/test/AElf.Contracts.Economic.TestBase/Types/MinerList.cs
@@ -8,7 +8,7 @@ namespace AElf.Contracts.Consensus.AEDPoS;
internal partial class MinerList
{
- public Round GenerateFirstRoundOfNewTerm(int miningInterval,
+ public Round GenerateFirstRound(int miningInterval,
Timestamp currentBlockTime, long currentRoundNumber = 0, long currentTermNumber = 0)
{
var sortedMiners =
@@ -41,4 +41,39 @@ orderby obj.Value descending
return round;
}
+
+ public NextTermInput GenerateFirstRoundOfNewTerm(int miningInterval, byte[] randomNumber,
+ Timestamp currentBlockTime, long currentRoundNumber = 0, long currentTermNumber = 0)
+ {
+ var sortedMiners =
+ (from obj in Pubkeys
+ .ToDictionary(miner => miner.ToHex(), miner => miner[0])
+ orderby obj.Value descending
+ select obj.Key).ToList();
+
+ var input = new NextTermInput();
+
+ for (var i = 0; i < sortedMiners.Count; i++)
+ {
+ var minerInRound = new MinerInRound();
+
+ // The first miner will be the extra block producer of first round of each term.
+ if (i == 0) minerInRound.IsExtraBlockProducer = true;
+
+ minerInRound.Pubkey = sortedMiners[i];
+ minerInRound.Order = i + 1;
+ minerInRound.ExpectedMiningTime = currentBlockTime.AddMilliseconds(i * miningInterval + miningInterval);
+ // Should be careful during validation.
+ minerInRound.PreviousInValue = Hash.Empty;
+
+ input.RealTimeMinersInformation.Add(sortedMiners[i], minerInRound);
+ }
+
+ input.RoundNumber = currentRoundNumber + 1;
+ input.TermNumber = currentTermNumber + 1;
+ input.IsMinerListJustChanged = true;
+ input.RandomNumber = ByteString.CopyFrom(randomNumber);
+
+ return input;
+ }
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.Economic.TestBase/Types/Round_Generation.cs b/test/AElf.Contracts.Economic.TestBase/Types/Round_Generation.cs
index 567ca6cf6a..f195933fff 100644
--- a/test/AElf.Contracts.Economic.TestBase/Types/Round_Generation.cs
+++ b/test/AElf.Contracts.Economic.TestBase/Types/Round_Generation.cs
@@ -1,16 +1,18 @@
using System.Collections.Generic;
using System.Linq;
using AElf.CSharp.Core;
+using AElf.Types;
+using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
namespace AElf.Contracts.Consensus.AEDPoS;
internal partial class Round
{
- public bool GenerateNextRoundInformation(Timestamp currentBlockTimestamp, Timestamp blockchainStartTimestamp,
- out Round nextRound)
+ public bool GenerateNextRoundInformation(Timestamp currentBlockTimestamp, Timestamp blockchainStartTimestamp, ByteString randomNumber,
+ out NextRoundInput nextRound)
{
- nextRound = new Round();
+ nextRound = new NextRoundInput();
var minersMinedCurrentRound = GetMinedMiners();
var minersNotMinedCurrentRound = GetNotMinedMiners();
@@ -62,7 +64,8 @@ public bool GenerateNextRoundInformation(Timestamp currentBlockTimestamp, Timest
nextRound.RealTimeMinersInformation.Values.First().IsExtraBlockProducer = true;
else
expectedExtraBlockProducer.IsExtraBlockProducer = true;
-
+ nextRound.RandomNumber = randomNumber;
+
return true;
}
diff --git a/test/AElf.Contracts.EconomicSystem.Tests/AElf.Contracts.EconomicSystem.Tests.csproj b/test/AElf.Contracts.EconomicSystem.Tests/AElf.Contracts.EconomicSystem.Tests.csproj
index c5333b816b..dbad41ec40 100644
--- a/test/AElf.Contracts.EconomicSystem.Tests/AElf.Contracts.EconomicSystem.Tests.csproj
+++ b/test/AElf.Contracts.EconomicSystem.Tests/AElf.Contracts.EconomicSystem.Tests.csproj
@@ -13,7 +13,7 @@
runtime; build; native; contentfiles; analyzers
-
+
all
@@ -75,10 +75,10 @@
Contract
PreserveNewest
-
-
-
-
+
+
+
+
false
Contract
@@ -99,9 +99,14 @@
Contract
PreserveNewest
-
-
-
+
+ false
+ Contract
+ PreserveNewest
+
+
+
+
@@ -222,5 +227,5 @@
-
+
diff --git a/test/AElf.Contracts.EconomicSystem.Tests/BVT/DonateTests.cs b/test/AElf.Contracts.EconomicSystem.Tests/BVT/DonateTests.cs
index db05af1544..4c3a80ae96 100644
--- a/test/AElf.Contracts.EconomicSystem.Tests/BVT/DonateTests.cs
+++ b/test/AElf.Contracts.EconomicSystem.Tests/BVT/DonateTests.cs
@@ -118,13 +118,14 @@ private async Task InitialBuildConnector(string symbol)
TokenSymbol = symbol,
AmountToTokenConvert = 0
};
- var issueRet = (await TransactionFeeChargingContractStub.IssueToTokenConvert.SendAsync(
- new IssueAmount
+ await TokenContractStub.Issue.SendAsync(
+ new IssueInput
{
Symbol = symbol,
- Amount = token.TotalSupply - token.Supply
- })).TransactionResult;
- issueRet.Status.ShouldBe(TransactionResultStatus.Mined);
+ Amount = token.TotalSupply - token.Supply,
+ To = TokenConverterContractAddress,
+ Memo = "test"
+ });
var buildConnector = (await TokenConverterContractStub.EnableConnector.SendAsync(tokenInfo)).TransactionResult;
buildConnector.Status.ShouldBe(TransactionResultStatus.Mined);
}
diff --git a/test/AElf.Contracts.EconomicSystem.Tests/BVT/TreasuryBasicTests.cs b/test/AElf.Contracts.EconomicSystem.Tests/BVT/TreasuryBasicTests.cs
index 44fa2b131a..24fc9e63d0 100644
--- a/test/AElf.Contracts.EconomicSystem.Tests/BVT/TreasuryBasicTests.cs
+++ b/test/AElf.Contracts.EconomicSystem.Tests/BVT/TreasuryBasicTests.cs
@@ -281,10 +281,11 @@ public async Task Treasury_SetSymbolList_With_Invalid_Token_Test()
TokenName = "TEST name",
TotalSupply = 1_0000_0000,
Issuer = BootMinerAddress,
- IsBurnable = true
+ IsBurnable = true,
+ Owner = BootMinerAddress
};
- var createTokenRet = await TokenContractStub.Create.SendAsync(tokenCreateInput);
- createTokenRet.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ await ExecuteProposalForParliamentTransactionWithException(Tester, TokenContractAddress, nameof(TokenContractStub.Create),
+ tokenCreateInput);
// without native token
{
var newSymbolList = new SymbolList
@@ -328,9 +329,11 @@ public async Task Treasury_SetSymbolList_Success_Test()
TokenName = "CWJ name",
TotalSupply = 1_0000_0000,
Issuer = BootMinerAddress,
- IsBurnable = true
+ IsBurnable = true,
+ Owner = BootMinerAddress
};
- await TokenContractStub.Create.SendAsync(tokenCreateInput);
+ await ExecuteProposalForParliamentTransaction(TokenContractAddress, nameof(TokenContractStub.Create),
+ tokenCreateInput);
var newSymbolList = new SymbolList
{
Value =
diff --git a/test/AElf.Contracts.Election.Tests/AElf.Contracts.Election.Tests.csproj b/test/AElf.Contracts.Election.Tests/AElf.Contracts.Election.Tests.csproj
index 4f04ca5c83..e472065cfe 100644
--- a/test/AElf.Contracts.Election.Tests/AElf.Contracts.Election.Tests.csproj
+++ b/test/AElf.Contracts.Election.Tests/AElf.Contracts.Election.Tests.csproj
@@ -40,6 +40,11 @@
Contract
PreserveNewest
+
+ false
+ Contract
+ PreserveNewest
+
@@ -52,6 +57,13 @@
Protobuf\Proto\transaction_fee.proto
+
+
+
+ Protobuf\Proto\test_virtual_address_contract.proto
+
+
+
diff --git a/test/AElf.Contracts.Election.Tests/BVT/ElectionTests.cs b/test/AElf.Contracts.Election.Tests/BVT/ElectionTests.cs
index ce2fac0ff9..2ba363f220 100644
--- a/test/AElf.Contracts.Election.Tests/BVT/ElectionTests.cs
+++ b/test/AElf.Contracts.Election.Tests/BVT/ElectionTests.cs
@@ -6,6 +6,7 @@
using AElf.Contracts.MultiToken;
using AElf.Contracts.Parliament;
using AElf.Contracts.Profit;
+using AElf.Contracts.TestContract.VirtualAddress;
using AElf.Contracts.Vote;
using AElf.Cryptography.ECDSA;
using AElf.CSharp.Core;
@@ -299,7 +300,7 @@ await VoteToCandidates(
{
Value = voterKeyPair.PublicKey.ToHex()
});
- voterVotes.Pubkey.ShouldBe(ByteString.CopyFrom(voterKeyPair.PublicKey));
+ voterVotes.Address.ShouldBe(Address.FromPublicKey(voterKeyPair.PublicKey));
voterVotes.ActiveVotingRecordIds.Count.ShouldBe(19);
voterVotes.AllVotedVotesAmount.ShouldBe(actualVotedAmount);
voterVotes.ActiveVotedVotesAmount.ShouldBe(actualVotedAmount);
@@ -1900,4 +1901,224 @@ private async Task ResetMinerCount(int count)
}
#endregion
+
+ [Fact]
+ public async Task VirtualAddress_Vote_Test()
+ {
+ var amount = 100;
+ const int lockTime = 100 * 60 * 60 * 24;
+ var candidatesKeyPairs = await ElectionContract_AnnounceElection_Test();
+ var candidateKeyPair = candidatesKeyPairs[0];
+
+ var address = await VirtualAddressContractStub.GetVirtualAddress.CallAsync(new Empty());
+ var initBalance = 100000;
+
+ await TokenContractStub.Transfer.SendAsync(new TransferInput
+ {
+ Amount = initBalance,
+ Symbol = "ELF",
+ To = address,
+ Memo = "test"
+ });
+
+ CheckBalance(address, "ELF", initBalance);
+ CheckBalance(address, "SHARE", 0);
+ CheckBalance(address, "VOTE", 0);
+
+ await VirtualAddressContractStub.VirtualAddressVote.SendAsync(new VirtualAddressVoteInput
+ {
+ PubKey = candidateKeyPair.PublicKey.ToHex(),
+ Amount = amount,
+ EndTimestamp = TimestampHelper.GetUtcNow().AddSeconds(lockTime),
+ Token = HashHelper.ComputeFrom("token A")
+ });
+
+ var result = await ElectionContractStub.GetElectorVote.CallAsync(new StringValue
+ {
+ Value = address.ToBase58()
+ });
+ result.ActiveVotedVotesAmount.ShouldBe(amount);
+ result = await ElectionContractStub.GetElectorVoteWithRecords.CallAsync(new StringValue
+ {
+ Value = address.ToBase58()
+ });
+ result.ActiveVotedVotesAmount.ShouldBe(amount);
+ result = await ElectionContractStub.GetElectorVoteWithAllRecords.CallAsync(new StringValue
+ {
+ Value = address.ToBase58()
+ });
+ result.AllVotedVotesAmount.ShouldBe(amount);
+
+ CheckBalance(address, "ELF", initBalance - amount);
+ CheckBalance(address, "SHARE", amount);
+ CheckBalance(address, "VOTE", amount);
+
+ await VirtualAddressContractStub.VirtualAddressVote.SendAsync(new VirtualAddressVoteInput
+ {
+ PubKey = candidateKeyPair.PublicKey.ToHex(),
+ Amount = amount,
+ EndTimestamp = TimestampHelper.GetUtcNow().AddSeconds(lockTime),
+ Token = HashHelper.ComputeFrom("token A")
+ });
+
+ result = await ElectionContractStub.GetElectorVote.CallAsync(new StringValue
+ {
+ Value = address.ToBase58()
+ });
+ result.ActiveVotedVotesAmount.ShouldBe(amount + amount);
+ result = await ElectionContractStub.GetElectorVoteWithRecords.CallAsync(new StringValue
+ {
+ Value = address.ToBase58()
+ });
+ result.ActiveVotedVotesAmount.ShouldBe(amount + amount);
+ result = await ElectionContractStub.GetElectorVoteWithAllRecords.CallAsync(new StringValue
+ {
+ Value = address.ToBase58()
+ });
+ result.AllVotedVotesAmount.ShouldBe(amount + amount);
+
+ CheckBalance(address, "ELF", initBalance - amount - amount);
+ CheckBalance(address, "SHARE", amount + amount);
+ CheckBalance(address, "VOTE", amount + amount);
+
+ return result.ActiveVotingRecords.First().VoteId;
+ }
+
+ [Fact]
+ public async Task VirtualAddress_Withdraw_Test()
+ {
+ var amount = 100;
+ const int lockTime = 100 * 60 * 60 * 24;
+
+ var address = await VirtualAddressContractStub.GetVirtualAddress.CallAsync(new Empty());
+ var initBalance = 100000;
+
+ var voteId = await VirtualAddress_Vote_Test();
+ BlockTimeProvider.SetBlockTime(TimestampHelper.GetUtcNow().AddDays(101));
+
+ await VirtualAddressContractStub.VirtualAddressWithdraw.SendAsync(new Hash
+ {
+ Value = voteId.Value
+ });
+
+ var result = await ElectionContractStub.GetElectorVote.CallAsync(new StringValue
+ {
+ Value = address.ToBase58()
+ });
+ result.ActiveVotedVotesAmount.ShouldBe(amount);
+ result = await ElectionContractStub.GetElectorVoteWithRecords.CallAsync(new StringValue
+ {
+ Value = address.ToBase58()
+ });
+ result.ActiveVotedVotesAmount.ShouldBe(amount);
+ result = await ElectionContractStub.GetElectorVoteWithAllRecords.CallAsync(new StringValue
+ {
+ Value = address.ToBase58()
+ });
+
+ result.ActiveVotedVotesAmount.ShouldBe(amount);
+ result.WithdrawnVotesRecords.Count().ShouldBe(1);
+ result.AllVotedVotesAmount.ShouldBe(amount + amount);
+
+ CheckBalance(address, "ELF", initBalance - amount);
+ CheckBalance(address, "SHARE", amount);
+ CheckBalance(address, "VOTE", amount);
+ }
+
+ [Fact]
+ public async Task Vote_Test()
+ {
+ var amount = 100;
+ const int lockTime = 100 * 60 * 60 * 24;
+ var candidatesKeyPairs = await ElectionContract_AnnounceElection_Test();
+ var candidateKeyPair = candidatesKeyPairs[0];
+
+ var address = Address.FromPublicKey(BootMinerKeyPair.PublicKey);
+ var initBalance = 100000000000000;
+
+ CheckBalance(address, "ELF", initBalance);
+ CheckBalance(address, "SHARE", 0);
+ CheckBalance(address, "VOTE", 0);
+
+ var voteRet = await ElectionContractStub.Vote.SendAsync(new VoteMinerInput
+ {
+ CandidatePubkey = candidateKeyPair.PublicKey.ToHex(),
+ Amount = amount,
+ EndTimestamp = TimestampHelper.GetUtcNow().AddSeconds(lockTime),
+ Token = HashHelper.ComputeFrom("token A")
+ });
+ voteRet.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+
+ var result = await ElectionContractStub.GetElectorVote.CallAsync(new StringValue
+ {
+ Value = BootMinerKeyPair.PublicKey.ToHex()
+ });
+ result.ActiveVotedVotesAmount.ShouldBe(amount);
+ result = await ElectionContractStub.GetElectorVoteWithRecords.CallAsync(new StringValue
+ {
+ Value = BootMinerKeyPair.PublicKey.ToHex()
+ });
+ result.ActiveVotedVotesAmount.ShouldBe(amount);
+ result = await ElectionContractStub.GetElectorVoteWithAllRecords.CallAsync(new StringValue
+ {
+ Value = BootMinerKeyPair.PublicKey.ToHex()
+ });
+ result.AllVotedVotesAmount.ShouldBe(amount);
+
+ CheckBalance(address, "ELF", initBalance - amount);
+ CheckBalance(address, "SHARE", amount);
+ CheckBalance(address, "VOTE", amount);
+
+ return result.ActiveVotingRecords.First().VoteId;
+ }
+
+ [Fact]
+ public async Task Withdraw_Test()
+ {
+ var voteId = await Vote_Test();
+
+ BlockTimeProvider.SetBlockTime(TimestampHelper.GetUtcNow().AddDays(101));
+
+ await ElectionContractStub.Withdraw.SendAsync(new Hash
+ {
+ Value = voteId.Value
+ });
+
+ var result = await ElectionContractStub.GetElectorVote.CallAsync(new StringValue
+ {
+ Value = BootMinerKeyPair.PublicKey.ToHex()
+ });
+ result.ActiveVotedVotesAmount.ShouldBe(0);
+ result = await ElectionContractStub.GetElectorVoteWithRecords.CallAsync(new StringValue
+ {
+ Value = BootMinerKeyPair.PublicKey.ToHex()
+ });
+ result.ActiveVotedVotesAmount.ShouldBe(0);
+ result = await ElectionContractStub.GetElectorVoteWithAllRecords.CallAsync(new StringValue
+ {
+ Value = BootMinerKeyPair.PublicKey.ToHex()
+ });
+
+ result.ActiveVotedVotesAmount.ShouldBe(0);
+ result.WithdrawnVotesRecords.Count().ShouldBe(1);
+ result.AllVotedVotesAmount.ShouldBe(100);
+
+ var address = Address.FromPublicKey(BootMinerKeyPair.PublicKey);
+ var initBalance = 100000000000000;
+
+ CheckBalance(address, "ELF", initBalance);
+ CheckBalance(address, "SHARE", 0);
+ CheckBalance(address, "VOTE", 0);
+ }
+
+ private void CheckBalance(Address address, string symbol, long amount)
+ {
+ var balance = TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Owner = address,
+ Symbol = symbol
+ }).Result;
+
+ balance.Balance.ShouldBe(amount);
+ }
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.Election.Tests/BVT/ElectionViewTests.cs b/test/AElf.Contracts.Election.Tests/BVT/ElectionViewTests.cs
index 61d8128ced..a8d4093af4 100644
--- a/test/AElf.Contracts.Election.Tests/BVT/ElectionViewTests.cs
+++ b/test/AElf.Contracts.Election.Tests/BVT/ElectionViewTests.cs
@@ -47,10 +47,7 @@ public async Task GetElectorVoteWithRecords_NotExist_Test()
{
Value = ValidationDataCenterKeyPairs.Last().PublicKey.ToHex()
});
- voteRecords.ShouldBe(new ElectorVote
- {
- Pubkey = ByteString.CopyFrom(ValidationDataCenterKeyPairs.Last().PublicKey)
- });
+ voteRecords.ShouldBe(new ElectorVote());
}
[Fact]
@@ -305,7 +302,7 @@ public async Task Election_GetElectorVote_Test()
{
Value = key
});
- ret.ShouldBe(new ElectorVote { Pubkey = ByteStringHelper.FromHexString(key) });
+ ret.ShouldBe(new ElectorVote());
}
[Fact]
diff --git a/test/AElf.Contracts.Election.Tests/ElectionContractTestBase.cs b/test/AElf.Contracts.Election.Tests/ElectionContractTestBase.cs
index 4375a2c352..6ba094c35d 100644
--- a/test/AElf.Contracts.Election.Tests/ElectionContractTestBase.cs
+++ b/test/AElf.Contracts.Election.Tests/ElectionContractTestBase.cs
@@ -5,9 +5,11 @@
using AElf.Contracts.MultiToken;
using AElf.Contracts.Parliament;
using AElf.Contracts.Profit;
+using AElf.Contracts.TestContract.VirtualAddress;
using AElf.Contracts.TokenConverter;
using AElf.Contracts.Treasury;
using AElf.Contracts.Vote;
+using AElf.ContractTestKit;
using AElf.Cryptography.ECDSA;
using AElf.Types;
using Google.Protobuf.WellKnownTypes;
@@ -17,6 +19,13 @@ namespace AElf.Contracts.Election;
public class ElectionContractTestBase : EconomicContractsTestBase
{
+ protected readonly IBlockTimeProvider BlockTimeProvider;
+
+ protected ElectionContractTestBase()
+ {
+ BlockTimeProvider = GetRequiredService();
+ }
+
protected Hash MinerElectionVotingItemId;
internal BasicContractZeroImplContainer.BasicContractZeroImplStub BasicContractZeroStub =>
@@ -48,6 +57,9 @@ public class ElectionContractTestBase : EconomicContractsTestBase
internal EconomicContractImplContainer.EconomicContractImplStub EconomicContractStub =>
GetEconomicContractTester(BootMinerKeyPair);
+ internal VirtualAddressContractContainer.VirtualAddressContractStub VirtualAddressContractStub =>
+ GetVirtualAddressContractTester(BootMinerKeyPair);
+
private new void DeployAllContracts()
{
_ = TokenContractAddress;
@@ -135,4 +147,9 @@ internal EconomicContractImplContainer.EconomicContractImplStub GetEconomicContr
{
return GetTester(EconomicContractAddress, keyPair);
}
+
+ internal VirtualAddressContractContainer.VirtualAddressContractStub GetVirtualAddressContractTester(ECKeyPair keyPair)
+ {
+ return GetTester(VirtualAddressContractAddress, keyPair);
+ }
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.Election.Tests/Full/BackupSubsidyTests.cs b/test/AElf.Contracts.Election.Tests/Full/BackupSubsidyTests.cs
index 48a1f5a9b2..c4d466b08f 100644
--- a/test/AElf.Contracts.Election.Tests/Full/BackupSubsidyTests.cs
+++ b/test/AElf.Contracts.Election.Tests/Full/BackupSubsidyTests.cs
@@ -618,6 +618,41 @@ await candidateAdminStub.SetProfitsReceiver.SendAsync(
}
}
+ [Fact]
+ public async Task SetProfitsReceiver_Wrong_Admin_Test()
+ {
+ var announceElectionKeyPair = ValidationDataCenterKeyPairs.First();
+ var candidateAdmin = ValidationDataCenterKeyPairs.Last();
+ var profitReceiver = candidateAdmin;
+ var candidateAdminAddress = Address.FromPublicKey(candidateAdmin.PublicKey);
+ await AnnounceElectionAsync(announceElectionKeyPair, candidateAdminAddress);
+
+ var candidateAdminStub =
+ GetTester(TreasuryContractAddress,
+ candidateAdmin);
+ await candidateAdminStub.SetProfitsReceiver.SendAsync(
+ new Treasury.SetProfitsReceiverInput
+ {
+ Pubkey = announceElectionKeyPair.PublicKey.ToHex(),
+ ProfitsReceiverAddress = Address.FromPublicKey(profitReceiver.PublicKey)
+ });
+ var getProfitReceiver = await GetProfitReceiver(announceElectionKeyPair.PublicKey.ToHex());
+ getProfitReceiver.ShouldBe(Address.FromPublicKey(profitReceiver.PublicKey));
+
+ var wrongAdminStub =
+ GetTester(TreasuryContractAddress,
+ announceElectionKeyPair);
+ var setResult = await wrongAdminStub.SetProfitsReceiver.SendWithExceptionAsync(
+ new Treasury.SetProfitsReceiverInput(new Treasury.SetProfitsReceiverInput
+ {
+ Pubkey = announceElectionKeyPair.PublicKey.ToHex(),
+ ProfitsReceiverAddress = Address.FromPublicKey(profitReceiver.PublicKey)
+ }));
+
+ setResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ setResult.TransactionResult.Error.ShouldContain("No permission.");
+ }
+
private async Task GetBackupSubsidyProfitDetails(Address address)
{
return await ProfitContractStub.GetProfitDetails.CallAsync(new GetProfitDetailsInput
diff --git a/test/AElf.Contracts.Genesis.Tests/AElf.Contracts.Genesis.Tests.csproj b/test/AElf.Contracts.Genesis.Tests/AElf.Contracts.Genesis.Tests.csproj
index fc5f102700..c439d16de0 100644
--- a/test/AElf.Contracts.Genesis.Tests/AElf.Contracts.Genesis.Tests.csproj
+++ b/test/AElf.Contracts.Genesis.Tests/AElf.Contracts.Genesis.Tests.csproj
@@ -33,6 +33,11 @@
Contract
PreserveNewest
+
+ false
+ Contract
+ PreserveNewest
+
diff --git a/test/AElf.Contracts.MultiToken.Tests/AElf.Contracts.MultiToken.Tests.csproj b/test/AElf.Contracts.MultiToken.Tests/AElf.Contracts.MultiToken.Tests.csproj
index 08ec6e2c33..a7de2a24a1 100644
--- a/test/AElf.Contracts.MultiToken.Tests/AElf.Contracts.MultiToken.Tests.csproj
+++ b/test/AElf.Contracts.MultiToken.Tests/AElf.Contracts.MultiToken.Tests.csproj
@@ -63,17 +63,18 @@
all
runtime; build; native; contentfiles; analyzers
-
+
-
+
+
- all
- runtime; build; native; contentfiles; analyzers
-
+ all
+ runtime; build; native; contentfiles; analyzers
+
- all
- runtime; build; native; contentfiles; analyzers
-
+ all
+ runtime; build; native; contentfiles; analyzers
+
@@ -134,6 +135,6 @@
Protobuf\Proto\base\acs11.proto
-
-
+
+
diff --git a/test/AElf.Contracts.MultiToken.Tests/BVT/ACS1_ImplementTest.cs b/test/AElf.Contracts.MultiToken.Tests/BVT/ACS1_ImplementTest.cs
index d50f4ad89d..ec111cbc73 100644
--- a/test/AElf.Contracts.MultiToken.Tests/BVT/ACS1_ImplementTest.cs
+++ b/test/AElf.Contracts.MultiToken.Tests/BVT/ACS1_ImplementTest.cs
@@ -129,7 +129,6 @@ public async Task SendInvalidTransactionsTest()
[Fact]
public async Task SetMethodFee_Success_Test()
{
- await CreateNativeTokenAsync();
var methodName = "Transfer";
var tokenSymbol = NativeTokenInfo.Symbol;
var basicFee = 100;
@@ -161,7 +160,6 @@ public async Task SetMethodFee_Success_Test()
[Fact]
public async Task SetMethodFee_Fail_Test()
{
- await CreateNativeTokenAsync();
var tokenSymbol = NativeTokenInfo.Symbol;
var methodName = "Transfer";
// unauthorized
@@ -212,11 +210,12 @@ public async Task SetMethodFee_Fail_Test()
// token is not profitable
{
var tokenNotProfitable = "DLS";
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateMutiTokenAsync(TokenContractStub,new CreateInput
{
Symbol = tokenNotProfitable,
TokenName = "name",
Issuer = DefaultAddress,
+ Owner = DefaultAddress,
TotalSupply = 1000_000
});
var methodFees = new MethodFees
@@ -239,7 +238,6 @@ public async Task GetMethodFee_No_Fee_Test(params string[] defaultSetMethodNames
{
var methodFeeController = await TokenContractStub.GetMethodFeeController.CallAsync(new Empty());
var proposalMethodName = nameof(TokenContractStub.SetMethodFee);
- await CreateNativeTokenAsync();
var tokenSymbol = NativeTokenInfo.Symbol;
var basicFee = 100;
foreach (var methodName in defaultSetMethodNames)
@@ -271,7 +269,6 @@ public async Task GetMethodFee_Fix_Fee_Test(params string[] defaultSetMethodName
{
var methodFeeController = await TokenContractStub.GetMethodFeeController.CallAsync(new Empty());
var proposalMethodName = nameof(TokenContractStub.SetMethodFee);
- await CreateNativeTokenAsync();
var tokenSymbol = NativeTokenInfo.Symbol;
var basicFee = 100;
foreach (var methodName in defaultSetMethodNames)
diff --git a/test/AElf.Contracts.MultiToken.Tests/BVT/ACS2_TokenResourceTests.cs b/test/AElf.Contracts.MultiToken.Tests/BVT/ACS2_TokenResourceTests.cs
index 45da7dc586..35f84f7154 100644
--- a/test/AElf.Contracts.MultiToken.Tests/BVT/ACS2_TokenResourceTests.cs
+++ b/test/AElf.Contracts.MultiToken.Tests/BVT/ACS2_TokenResourceTests.cs
@@ -1,4 +1,11 @@
+using System.Collections.Generic;
using System.Threading.Tasks;
+using AElf.CSharp.Core.Extension;
+using AElf.Kernel;
+using AElf.Standards.ACS1;
+using AElf.Standards.ACS3;
+using AElf.Types;
+using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using Shouldly;
using Xunit;
@@ -42,6 +49,139 @@ public async Task ACS2_GetResourceInfo_TransferFrom_Test()
result.WritePaths.Count.ShouldBeGreaterThan(0);
}
+ private async Task GetDefaultParliamentAddressAsync()
+ {
+ var defaultParliamentAddress =
+ await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
+ return defaultParliamentAddress;
+ }
+
+ [Fact]
+ public async Task ACS2_GetResourceInfo_Transfer_MultiToken_Test()
+ {
+ var theDefaultController = await GetDefaultParliamentAddressAsync();
+ var newSymbolList = new SymbolListToPayTxSizeFee();
+ await CreateTokenAsync(DefaultAddress, "CPU");
+ await CreateTokenAsync(DefaultAddress, "NET");
+ var methodName = "Transfer";
+ var tokenSymbol = "NET";
+ var basicFee = 100;
+ var methodFeeController = await TokenContractStub.GetMethodFeeController.CallAsync(new Empty());
+ var proposalMethodName = nameof(TokenContractStub.SetMethodFee);
+ var methodFees = new MethodFees
+ {
+ MethodName = methodName,
+ Fees =
+ {
+ new MethodFee { Symbol = tokenSymbol, BasicFee = basicFee }
+ }
+ };
+ var proposalId = await CreateProposalAsync(TokenContractAddress,
+ methodFeeController.OwnerAddress, proposalMethodName, methodFees);
+ await ApproveWithMinersAsync(proposalId);
+ var releaseResult = await ParliamentContractStub.Release.SendAsync(proposalId);
+ releaseResult.TransactionResult.Error.ShouldBeNullOrEmpty();
+ releaseResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ newSymbolList.SymbolsToPayTxSizeFee.Add(new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = "ELF",
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ });
+ newSymbolList.SymbolsToPayTxSizeFee.Add(new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = "CPU",
+ AddedTokenWeight = 2,
+ BaseTokenWeight = 1
+ });
+ var createProposalInput = new CreateProposalInput
+ {
+ ToAddress = TokenContractAddress,
+ Params = newSymbolList.ToByteString(),
+ OrganizationAddress = theDefaultController,
+ ContractMethodName = nameof(TokenContractImplContainer.TokenContractImplStub
+ .SetSymbolsToPayTxSizeFee),
+ ExpiredTime = TimestampHelper.GetUtcNow().AddHours(1)
+ };
+ var parliamentCreateProposal = await ParliamentContractStub.CreateProposal.SendAsync(createProposalInput);
+ var parliamentProposalId = parliamentCreateProposal.Output;
+ foreach (var bp in InitialCoreDataCenterKeyPairs)
+ {
+ var tester = GetParliamentContractTester(bp);
+ var approveResult = await tester.Approve.SendAsync(parliamentProposalId);
+ approveResult.TransactionResult.Error.ShouldBeNullOrEmpty();
+ }
+ var transactionRelease = ParliamentContractStub.Release.GetTransaction(parliamentProposalId);
+ await ExecuteTransactionWithMiningAsync(transactionRelease);
+ var symbolListToPayTxSizeFee = await TokenContractStub.GetSymbolsToPayTxSizeFee.CallAsync(new Empty());
+ symbolListToPayTxSizeFee.SymbolsToPayTxSizeFee.Count.ShouldBeGreaterThan(0);
+ var transaction = GenerateTokenTransaction(Accounts[0].Address, nameof(TokenContractStub.Transfer),
+ new TransferFromInput
+ {
+ Amount = 100,
+ Symbol = "ELF",
+ From = Accounts[1].Address,
+ To = Accounts[2].Address,
+ Memo = "Test get resource"
+ });
+
+ var result1 = await Acs2BaseStub.GetResourceInfo.CallAsync(transaction);
+ result1.NonParallelizable.ShouldBeFalse();
+ result1.WritePaths.Count.ShouldBeGreaterThan(0);
+ }
+
+ [Fact]
+ public async Task ACS2_GetResourceInfo_TransferFrom_WithDelegate_Test()
+ {
+ var delegations1 = new Dictionary
+ {
+ [NativeToken] = 1000,
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractStub.TransferFrom),
+ Delegations =
+ {
+ delegations1
+ },
+ IsUnlimitedDelegate = false
+ };
+ await TokenContractStubUser.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = Accounts[0].Address,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ await TokenContractStubDelegate.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = Accounts[0].Address,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ await TokenContractStubDelegate2.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ await TokenContractStubDelegate3.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User2Address,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ var transaction = GenerateTokenTransaction(Accounts[0].Address, nameof(TokenContractStub.TransferFrom),
+ new TransferFromInput
+ {
+ Amount = 100,
+ Symbol = NativeToken,
+ From = Accounts[1].Address,
+ To = Accounts[2].Address,
+ Memo = "Test get resource"
+ });
+
+ var result = await Acs2BaseStub.GetResourceInfo.CallAsync(transaction);
+ result.NonParallelizable.ShouldBeFalse();
+ result.WritePaths.Count.ShouldBe(9);
+
+ }
[Fact]
public async Task ACS2_GetResourceInfo_DonateResourceToken_Test()
{
diff --git a/test/AElf.Contracts.MultiToken.Tests/BVT/NftApplicationTests.cs b/test/AElf.Contracts.MultiToken.Tests/BVT/NftApplicationTests.cs
index ce5e3c2c8e..24055b432b 100644
--- a/test/AElf.Contracts.MultiToken.Tests/BVT/NftApplicationTests.cs
+++ b/test/AElf.Contracts.MultiToken.Tests/BVT/NftApplicationTests.cs
@@ -2,6 +2,8 @@
using System.Linq;
using System.Threading.Tasks;
using AElf.CSharp.Core;
+using AElf.CSharp.Core.Extension;
+using AElf.Kernel;
using AElf.Types;
using Google.Protobuf.WellKnownTypes;
using Shouldly;
@@ -44,7 +46,8 @@ public partial class MultiTokenContractTests
"https://i.seadn.io/gcs/files/0f5cdfaaf687de2ebb5834b129a5bef3.png?auto=format&w=3840"
}
}
- }
+ },
+ Owner = Accounts[0].Address
};
private TokenInfo NftCollection1155Info => new()
@@ -75,6 +78,7 @@ public partial class MultiTokenContractTests
TotalSupply = 1,
Decimals = 0,
Issuer = Accounts[0].Address,
+ Owner = Accounts[0].Address,
IssueChainId = _chainId,
IsBurnable = true,
ExternalInfo = new ExternalInfo()
@@ -113,14 +117,14 @@ public partial class MultiTokenContractTests
private async Task> CreateNftCollectionAsync(TokenInfo collectionInfo)
{
- await CreateNativeTokenAsync();
- return await TokenContractStub.Create.SendAsync(new CreateInput
+ return await CreateMutiTokenAsync(TokenContractStub, new CreateInput
{
Symbol = $"{collectionInfo.Symbol}0",
TokenName = collectionInfo.TokenName,
TotalSupply = collectionInfo.TotalSupply,
Decimals = collectionInfo.Decimals,
Issuer = collectionInfo.Issuer,
+ Owner = collectionInfo.Issuer,
IssueChainId = collectionInfo.IssueChainId,
ExternalInfo = collectionInfo.ExternalInfo
});
@@ -137,7 +141,8 @@ private async Task> CreateNftAsync(string colllectionSym
Issuer = nftInfo.Issuer,
IsBurnable = nftInfo.IsBurnable,
IssueChainId = nftInfo.IssueChainId,
- ExternalInfo = nftInfo.ExternalInfo
+ ExternalInfo = nftInfo.ExternalInfo,
+ Owner = nftInfo.Issuer
});
}
@@ -208,11 +213,10 @@ public async Task MultiTokenContract_Create_721Nft_Test()
[Fact(DisplayName = "[MultiToken_Nft] Create nft collection input check")]
public async Task MultiTokenContract_Create_NFTCollection_Input_Check_Test()
{
- await CreateNativeTokenAsync();
var input = NftCollection721Info;
// Decimals check
{
- var result = await TokenContractStub.Create.SendWithExceptionAsync(new CreateInput
+ var result = await CreateMutiTokenWithExceptionAsync(TokenContractStub, new CreateInput
{
Symbol = $"{input.Symbol}0",
TokenName = input.TokenName,
@@ -220,14 +224,15 @@ public async Task MultiTokenContract_Create_NFTCollection_Input_Check_Test()
Decimals = 8,
Issuer = input.Issuer,
IssueChainId = input.IssueChainId,
- ExternalInfo = input.ExternalInfo
+ ExternalInfo = input.ExternalInfo,
+ Owner = input.Owner
});
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
result.TransactionResult.Error.ShouldContain("NFT's decimals must be 0");
}
// Symbol check
{
- var result = await TokenContractStub.Create.SendWithExceptionAsync(new CreateInput
+ var seedInput = BuildSeedCreateInput( new CreateInput
{
Symbol = "ABC123",
TokenName = input.TokenName,
@@ -235,14 +240,17 @@ public async Task MultiTokenContract_Create_NFTCollection_Input_Check_Test()
Decimals = input.Decimals,
Issuer = input.Issuer,
IssueChainId = input.IssueChainId,
- ExternalInfo = input.ExternalInfo
+ ExternalInfo = input.ExternalInfo,
+ Owner = input.Owner
});
+
+ var result = await TokenContractStub.Create.SendWithExceptionAsync(seedInput);;
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
result.TransactionResult.Error.ShouldContain("Invalid Symbol input");
}
// Symbol length check
{
- var result = await TokenContractStub.Create.SendWithExceptionAsync(new CreateInput
+ var seedInput = BuildSeedCreateInput( new CreateInput
{
Symbol = "ABCDEFGHIJKLMNOPQRSTUVWXYZABC-0",
TokenName = input.TokenName,
@@ -250,23 +258,27 @@ public async Task MultiTokenContract_Create_NFTCollection_Input_Check_Test()
Decimals = input.Decimals,
Issuer = input.Issuer,
IssueChainId = input.IssueChainId,
- ExternalInfo = input.ExternalInfo
+ ExternalInfo = input.ExternalInfo,
+ Owner = input.Owner
});
+ var result = await TokenContractStub.Create.SendWithExceptionAsync(seedInput);;
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
result.TransactionResult.Error.ShouldContain("Invalid NFT symbol length");
}
// Issue chain Id check
{
- var result = await TokenContractStubUser.Create.SendAsync(new CreateInput
+ var result = await CreateMutiTokenAsync(TokenContractStub, new CreateInput
{
- Symbol = $"{input.Symbol}0",
+ Symbol = AliceCoinTokenInfo.Symbol,
TokenName = input.TokenName,
TotalSupply = input.TotalSupply,
Decimals = input.Decimals,
Issuer = NftCollection721Info.Issuer,
+ Owner = NftCollection721Info.Issuer,
IssueChainId = ChainHelper.ConvertBase58ToChainId("tDVV"),
ExternalInfo = input.ExternalInfo
});
+
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
}
}
@@ -279,9 +291,9 @@ public async Task MultiTokenContract_Create_NFT_Input_Check_Test()
// Decimals check
{
- var result = await TokenContractStub.Create.SendWithExceptionAsync(new CreateInput
+ var result = await CreateMutiTokenWithExceptionAsync(TokenContractStub, new CreateInput
{
- Symbol = $"{NftCollection721Info.Symbol}{input.Symbol}",
+ Symbol = "GHJ-0",
TokenName = input.TokenName,
TotalSupply = input.TotalSupply,
Decimals = 8,
@@ -294,7 +306,7 @@ public async Task MultiTokenContract_Create_NFT_Input_Check_Test()
}
// Symbol check
{
- var result = await TokenContractStub.Create.SendWithExceptionAsync(new CreateInput
+ var result = await CreateSeedNftWithExceptionAsync(TokenContractStub, new CreateInput
{
Symbol = "ABC-ABC",
TokenName = input.TokenName,
@@ -309,7 +321,7 @@ public async Task MultiTokenContract_Create_NFT_Input_Check_Test()
}
// Symbol check
{
- var result = await TokenContractStub.Create.SendWithExceptionAsync(new CreateInput
+ var result = await CreateSeedNftWithExceptionAsync(TokenContractStub, new CreateInput
{
Symbol = "ABC-",
TokenName = input.TokenName,
@@ -324,7 +336,7 @@ public async Task MultiTokenContract_Create_NFT_Input_Check_Test()
}
// Symbol check
{
- var result = await TokenContractStub.Create.SendWithExceptionAsync(new CreateInput
+ var result = await CreateSeedNftWithExceptionAsync(TokenContractStub, new CreateInput
{
Symbol = "ABC-ABC-1",
TokenName = input.TokenName,
@@ -347,13 +359,14 @@ public async Task MultiTokenContract_Create_NFT_Input_Check_Test()
Decimals = input.Decimals,
Issuer = Accounts.Last().Address,
IssueChainId = input.IssueChainId,
- ExternalInfo = input.ExternalInfo
+ ExternalInfo = input.ExternalInfo,
+ Owner = Accounts.Last().Address
});
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
- result.TransactionResult.Error.ShouldContain("NFT issuer must be collection's issuer");
+ result.TransactionResult.Error.ShouldContain("NFT owner must be collection's owner");
}
{
- var result = await TokenContractStubUser.Create.SendWithExceptionAsync(new CreateInput
+ var result = await TokenContractStub.Create.SendWithExceptionAsync( new CreateInput
{
Symbol = $"{NftCollection721Info.Symbol}{input.Symbol}",
TokenName = input.TokenName,
@@ -361,7 +374,8 @@ public async Task MultiTokenContract_Create_NFT_Input_Check_Test()
Decimals = input.Decimals,
Issuer = input.Issuer,
IssueChainId = ChainHelper.ConvertBase58ToChainId("tDVV"),
- ExternalInfo = input.ExternalInfo
+ ExternalInfo = input.ExternalInfo,
+ Owner = input.Owner
});
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
result.TransactionResult.Error.ShouldContain("NFT create ChainId must be collection's issue chainId");
@@ -371,7 +385,6 @@ public async Task MultiTokenContract_Create_NFT_Input_Check_Test()
[Fact(DisplayName = "[MultiToken_Nft] Collection not exist")]
public async Task MultiTokenContract_Create_NFT_Collection_NotExist()
{
- await CreateNativeTokenAsync();
var input = Nft721Info;
var result = await TokenContractStub.Create.SendWithExceptionAsync(new CreateInput
{
@@ -381,7 +394,8 @@ public async Task MultiTokenContract_Create_NFT_Collection_NotExist()
Decimals = input.Decimals,
Issuer = input.Issuer,
IssueChainId = input.IssueChainId,
- ExternalInfo = input.ExternalInfo
+ ExternalInfo = input.ExternalInfo,
+ Owner = input.Owner
});
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
result.TransactionResult.Error.ShouldContain("NFT collection not exist");
@@ -400,7 +414,8 @@ public async Task MultiTokenContract_Create_NFT_Already_Exist()
Decimals = input.Decimals,
Issuer = input.Issuer,
IssueChainId = input.IssueChainId,
- ExternalInfo = input.ExternalInfo
+ ExternalInfo = input.ExternalInfo,
+ Owner = input.Owner
});
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
result.TransactionResult.Error.ShouldContain("Token already exists.");
@@ -669,4 +684,212 @@ public async Task NftIssue_Approve_TransferFrom()
});
ownerBalanceOutput.Balance.ShouldBe(90);
}
+
+ [Fact(DisplayName = "[token] create Test")]
+ public async Task CreateTokenTest()
+ {
+ var res = await CreateMutiTokenAsync(TokenContractStub, new CreateInput
+ {
+ Symbol = "XYZ",
+ TokenName = "Trump Digital Trading Cards #1155",
+ TotalSupply = TotalSupply,
+ Decimals = 0,
+ Issuer = DefaultAddress,
+ Owner = DefaultAddress,
+ IssueChainId = _chainId,
+ });
+ res.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ // check symbol repeat
+ var exceptionRes = await CreateSeedNftWithExceptionAsync(TokenContractStub, new CreateInput
+ {
+ Symbol = "XYZ",
+ TokenName = "Trump Digital Trading Cards #1155",
+ TotalSupply = TotalSupply,
+ Decimals = 0,
+ Issuer = DefaultAddress,
+ IssueChainId = _chainId,
+ });
+ exceptionRes.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ exceptionRes.TransactionResult.Error.ShouldContain("Token already exists");
+ // check collection symbol prefix duplicated
+ var failCollection = await CreateSeedNftWithExceptionAsync(TokenContractStub, new CreateInput
+ {
+ TokenName = "Trump Digital Trading Cards #1155",
+ TotalSupply = TotalSupply,
+ Decimals = 0,
+ Issuer = DefaultAddress,
+ IssueChainId = _chainId,
+ Symbol = "XYZ-0"
+ });
+ failCollection.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ failCollection.TransactionResult.Error.ShouldContain("Token already exists.");
+
+ var successCollection = await CreateMutiTokenAsync(TokenContractStub, new CreateInput
+ {
+ TokenName = "Trump Digital Trading Cards #1155",
+ TotalSupply = TotalSupply,
+ Decimals = 0,
+ Issuer = DefaultAddress,
+ Owner = DefaultAddress,
+ IssueChainId = _chainId,
+ Symbol = "GHJ-0"
+ });
+ successCollection.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ // check ft symbol prefix duplicated
+ var fTokenAsync = await CreateSeedNftWithExceptionAsync(TokenContractStub, new CreateInput
+ {
+ TokenName = "Trump Digital Trading Cards #1155",
+ TotalSupply = TotalSupply,
+ Decimals = 0,
+ Issuer = DefaultAddress,
+ IssueChainId = _chainId,
+ Symbol = "GHJ"
+ });
+ fTokenAsync.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ fTokenAsync.TransactionResult.Error.ShouldContain("Token already exists.");
+
+
+ var createInput = BuildSeedCreateInput(new CreateInput()
+ {
+ Symbol = "GH"
+ });
+ createInput.ExternalInfo.Value["__seed_owned_symbol"] = "";
+ var ownError = await TokenContractStub.Create.SendWithExceptionAsync(createInput);
+ ownError.TransactionResult.Error.ShouldContain("Invalid Symbol input");
+ var createInputExpire = BuildSeedCreateInput(new CreateInput()
+ {
+ Symbol = "GHT"
+ });
+ createInputExpire.ExternalInfo.Value["__seed_exp_time"] = "1234";
+ var expireError = await TokenContractStub.Create.SendWithExceptionAsync(createInputExpire);
+ expireError.TransactionResult.Error.ShouldContain("Invalid ownedSymbol.");
+ // create nft
+ var nftSuccessAsync = await TokenContractStub.Create.SendAsync(new CreateInput
+ {
+ TokenName = "Trump Digital Trading Cards #1155",
+ TotalSupply = TotalSupply,
+ Decimals = 0,
+ Issuer = DefaultAddress,
+ Owner = DefaultAddress,
+ IssueChainId = _chainId,
+ Symbol = "GHJ-1"
+ });
+ nftSuccessAsync.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ }
+
+ // [Fact(DisplayName = "[feed nft] create Test")]
+ // public async Task FeedNftCreateTest()
+ // {
+ // // symbol expire reCreate success
+ // var createInput = await CreateSeedNftAsync(TokenContractStub, new CreateInput
+ // {
+ // Issuer = DefaultAddress,
+ // Symbol = "XYZ-0"
+ // });
+ //
+ // createInput.ExternalInfo.Value["__seed_exp_time"] = "1234";
+ // await TokenContractStub.ResetExternalInfo.SendAsync(new ResetExternalInfoInput()
+ // {
+ // Symbol = createInput.Symbol,
+ // ExternalInfo = createInput.ExternalInfo
+ // });
+ //
+ // var input = BuildSeedCreateInput(new CreateInput
+ // {
+ // Issuer = DefaultAddress,
+ // Symbol = "XYZ-0"
+ // });
+ // var seedRes = await TokenContractStub.Create.SendAsync(input);
+ // seedRes.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ //
+ // // owner doesn't own enough balance
+ // var nftAsync = await TokenContractStub.Create.SendWithExceptionAsync(GetCreateInput());
+ // nftAsync.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ // nftAsync.TransactionResult.Error.ShouldContain("Seed NFT balance is not enough");
+ // // ExternalInfo check
+ // await TokenContractStub.Issue.SendAsync(new IssueInput
+ // {
+ // Symbol = input.Symbol,
+ // Amount = 1,
+ // Memo = "ddd",
+ // To = DefaultAddress
+ // });
+ // input.ExternalInfo.Value["__seed_owned_symbol"] = "XY-0";
+ //
+ // await TokenContractStub.ResetExternalInfo.SendAsync(new ResetExternalInfoInput()
+ // {
+ // Symbol = input.Symbol,
+ // ExternalInfo = input.ExternalInfo
+ // });
+ // var inconsistentExceptionAsync = await TokenContractStub.Create.SendWithExceptionAsync(GetCreateInput());
+ // inconsistentExceptionAsync.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ // inconsistentExceptionAsync.TransactionResult.Error.ShouldContain(
+ // "Invalid OwnedSymbol");
+ //
+ // input.ExternalInfo.Value["__seed_owned_symbol"] = "XYZ-0";
+ // input.ExternalInfo.Value["__seed_exp_time"] = "";
+ // await TokenContractStub.ResetExternalInfo.SendAsync(new ResetExternalInfoInput()
+ // {
+ // Symbol = input.Symbol,
+ // ExternalInfo = input.ExternalInfo
+ // });
+ // var expireExceptionAsync = await TokenContractStub.Create.SendWithExceptionAsync(
+ // GetCreateInput());
+ // expireExceptionAsync.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ // expireExceptionAsync.TransactionResult.Error.ShouldContain("OwnedSymbol is expired");
+ //
+ // input.ExternalInfo.Value["__seed_owned_symbol"] = "XYZ-0";
+ // input.ExternalInfo.Value["__seed_exp_time"] = "1234";
+ // await TokenContractStub.ResetExternalInfo.SendAsync(new ResetExternalInfoInput()
+ // {
+ // Symbol = input.Symbol,
+ // ExternalInfo = input.ExternalInfo
+ // });
+ // var expireExceptionAsync1 = await TokenContractStub.Create.SendWithExceptionAsync(GetCreateInput());
+ // expireExceptionAsync1.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ // expireExceptionAsync1.TransactionResult.Error.ShouldContain("OwnedSymbol is expired");
+ // await TokenContractStub.ResetExternalInfo.SendAsync(new ResetExternalInfoInput
+ // {
+ // Symbol = input.Symbol,
+ // ExternalInfo = new ExternalInfo()
+ // });
+ // var emptyExceptionAsync = await TokenContractStub.Create.SendWithExceptionAsync(GetCreateInput());
+ // emptyExceptionAsync.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ // emptyExceptionAsync.TransactionResult.Error.ShouldContain("Invalid OwnedSymbol");
+ // input.ExternalInfo.Value["__seed_owned_symbol"] = "XYZ-0";
+ // input.ExternalInfo.Value["__seed_exp_time"] = TimestampHelper.GetUtcNow().AddDays(1).Seconds.ToString();
+ // await TokenContractStub.ResetExternalInfo.SendAsync(new ResetExternalInfoInput
+ // {
+ // Symbol = input.Symbol,
+ // ExternalInfo = input.ExternalInfo
+ // });
+ // var re = await SubmitAndApproveProposalOfDefaultParliamentWithException(TokenContractAddress,
+ // nameof(TokenContractStub.Create), new CreateInput
+ // {
+ // Symbol = "XYZ-0",
+ // Decimals = 0,
+ // IsBurnable = true,
+ // TokenName = "ELF2",
+ // TotalSupply = 100_000_000_000_000_000L,
+ // Issuer = DefaultAddress,
+ // ExternalInfo = new ExternalInfo()
+ // });
+ // re.TransactionResult.Error.ShouldContain("OwnedSymbol has been created");
+ // re.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ //
+ //
+ // }
+
+ private CreateInput GetCreateInput()
+ {
+ return new CreateInput
+ {
+ TokenName = "Trump Digital Trading Cards #1155",
+ TotalSupply = TotalSupply,
+ Decimals = 0,
+ Issuer = DefaultAddress,
+ IssueChainId = _chainId,
+ Symbol = "XYZ-0"
+ };
+ }
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.MultiToken.Tests/BVT/TokenApplicationTests.cs b/test/AElf.Contracts.MultiToken.Tests/BVT/TokenApplicationTests.cs
index 137c034a2d..b4aa6e54d7 100644
--- a/test/AElf.Contracts.MultiToken.Tests/BVT/TokenApplicationTests.cs
+++ b/test/AElf.Contracts.MultiToken.Tests/BVT/TokenApplicationTests.cs
@@ -5,6 +5,7 @@
using AElf.Contracts.TestContract.BasicFunction;
using AElf.CSharp.Core;
using AElf.CSharp.Core.Extension;
+using AElf.Kernel;
using AElf.Standards.ACS10;
using AElf.Types;
using Google.Protobuf.WellKnownTypes;
@@ -15,6 +16,7 @@ namespace AElf.Contracts.MultiToken;
public partial class MultiTokenContractTests
{
+ protected const string SymbolForTest = "GHJ";
[Fact(DisplayName = "[MultiToken] Transfer token test")]
public async Task MultiTokenContract_Transfer_Test()
{
@@ -372,12 +374,13 @@ private async Task CreateTokenAndIssue(List whitelist = null, Address i
OtherBasicFunctionContractAddress,
TreasuryContractAddress
};
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateMutiTokenAsync(TokenContractStub,new CreateInput
{
Symbol = SymbolForTest,
Decimals = 2,
IsBurnable = true,
Issuer = DefaultAddress,
+ Owner = DefaultAddress,
TokenName = "elf test token",
TotalSupply = DPoSContractConsts.LockTokenForElection * 1000000,
LockWhiteList =
@@ -811,14 +814,15 @@ public async Task MultiTokenContract_Burn_Invalid_Token_Test()
{
await CreateAndIssueMultiTokensAsync();
var unburnedTokenSymbol = "UNBURNED";
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateMutiTokenAsync(TokenContractStub, new CreateInput
{
Symbol = unburnedTokenSymbol,
TokenName = "Name",
TotalSupply = 100_000_000_000L,
Decimals = 10,
IsBurnable = false,
- Issuer = DefaultAddress
+ Issuer = DefaultAddress,
+ Owner = DefaultAddress,
});
var burnRet = await TokenContractStub.Burn.SendWithExceptionAsync(new BurnInput
{
@@ -940,69 +944,6 @@ await BasicFunctionContractStub.TransferTokenToContract.SendAsync(
afterBalance.Balance.ShouldBe(beforeBalance.Balance.Add(transferAmount));
}
- [Fact(DisplayName = "[MultiToken] ChangeTokenIssuer test")]
- public async Task ChangeTokenIssuer_Test()
- {
- const string tokenSymbol = "PO";
- await CreateAndIssueMultiTokensAsync();
- await TokenContractStub.Create.SendAsync(new CreateInput
- {
- Symbol = tokenSymbol,
- TokenName = "Name",
- TotalSupply = 100_000_000_000L,
- Decimals = 10,
- IsBurnable = true,
- Issuer = Accounts[1].Address
- });
- var tokenIssuerStub =
- GetTester(TokenContractAddress, Accounts[1].KeyPair);
-
- {
- var issueNotExistTokenRet = await tokenIssuerStub.ChangeTokenIssuer.SendWithExceptionAsync(
- new ChangeTokenIssuerInput
- {
- Symbol = "NOTEXIST",
- NewTokenIssuer = Accounts[2].Address
- });
- issueNotExistTokenRet.TransactionResult.Error.ShouldContain("invalid token symbol");
- }
- {
- await tokenIssuerStub.ChangeTokenIssuer.SendAsync(new ChangeTokenIssuerInput
- {
- Symbol = tokenSymbol,
- NewTokenIssuer = Accounts[2].Address
- });
- var tokenInfo = await tokenIssuerStub.GetTokenInfo.CallAsync(new GetTokenInfoInput
- {
- Symbol = tokenSymbol
- });
- tokenInfo.Issuer.ShouldBe(Accounts[2].Address);
- }
- }
-
- [Fact(DisplayName = "[MultiToken] sender is not the token issuer")]
- public async Task ChangeTokenIssuer_Without_Authorization_Test()
- {
- const string tokenSymbol = "PO";
- await CreateAndIssueMultiTokensAsync();
- await TokenContractStub.Create.SendAsync(new CreateInput
- {
- Symbol = tokenSymbol,
- TokenName = "Name",
- TotalSupply = 100_000_000_000L,
- Decimals = 10,
- IsBurnable = true,
- Issuer = Accounts[1].Address
- });
- var changeIssuerRet = await TokenContractStub.ChangeTokenIssuer.SendWithExceptionAsync(
- new ChangeTokenIssuerInput
- {
- Symbol = tokenSymbol,
- NewTokenIssuer = Accounts[2].Address
- });
- changeIssuerRet.TransactionResult.Error.ShouldContain("permission denied");
- }
-
[Fact(DisplayName = "[MultiToken] Token initialize from parent chain test")]
public async Task InitializeFromParent_Test()
{
@@ -1064,7 +1005,8 @@ public async Task Side_Chain_Creat_Token_Test()
TokenName = "Ali",
Decimals = 4,
TotalSupply = 100_000,
- Issuer = DefaultAddress
+ Issuer = DefaultAddress,
+ Owner = DefaultAddress
});
createTokenRet.TransactionResult.Error.ShouldContain(
"Failed to create token if side chain creator already set.");
@@ -1078,7 +1020,6 @@ public async Task Side_Chain_Creat_Token_Test()
public async Task CheckThreshold_With_One_Token_Test(long totalSupply, long issueAmount, long ApproveAmount,
long checkAmount, bool isCheckAllowance, bool isThrowException)
{
- await CreateNativeTokenAsync();
var tokenA = "AITA";
await CreateAndIssueCustomizeTokenAsync(DefaultAddress, tokenA, totalSupply, issueAmount);
if (ApproveAmount > 0)
@@ -1122,7 +1063,6 @@ await TokenContractStub.Approve.SendAsync(new ApproveInput
public async Task CheckThreshold_With_Multiple_Token_Test(long tokenACheckAmount, long tokenAApporveAmount,
long tokenBCheckAmount, long tokenBApporveAmount, bool isCheckAllowance, bool isThrowException)
{
- await CreateNativeTokenAsync();
var tokenA = "AITA";
await CreateAndIssueCustomizeTokenAsync(DefaultAddress, tokenA, 10000, 1000);
var tokenB = "AITB";
@@ -1170,10 +1110,11 @@ private async Task CreateAndIssueCustomizeTokenAsync(Address creator, string sym
long issueAmount,
Address to = null, params string[] otherParameters)
{
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateMutiTokenAsync(TokenContractStub,new CreateInput
{
Symbol = symbol,
Issuer = creator,
+ Owner = creator,
TokenName = symbol + "name",
TotalSupply = totalSupply,
Decimals = 4
@@ -1189,14 +1130,14 @@ await TokenContractStub.Issue.SendAsync(new IssueInput
[Fact]
public async Task ValidateTokenInfoExists_ExternalInfo_Test()
{
- await CreateNativeTokenAsync();
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateMutiTokenAsync(TokenContractStub, new CreateInput
{
Symbol = AliceCoinTokenInfo.Symbol,
TokenName = AliceCoinTokenInfo.TokenName,
TotalSupply = AliceCoinTokenInfo.TotalSupply,
Decimals = AliceCoinTokenInfo.Decimals,
Issuer = AliceCoinTokenInfo.Issuer,
+ Owner = AliceCoinTokenInfo.Issuer,
IsBurnable = AliceCoinTokenInfo.IsBurnable,
LockWhiteList =
{
@@ -1215,6 +1156,7 @@ await TokenContractStub.Create.SendAsync(new CreateInput
TotalSupply = AliceCoinTokenInfo.TotalSupply,
Decimals = AliceCoinTokenInfo.Decimals,
Issuer = AliceCoinTokenInfo.Issuer,
+ Owner = AliceCoinTokenInfo.Issuer,
IsBurnable = AliceCoinTokenInfo.IsBurnable,
IssueChainId = _chainId
});
@@ -1229,6 +1171,7 @@ await TokenContractStub.Create.SendAsync(new CreateInput
TotalSupply = AliceCoinTokenInfo.TotalSupply,
Decimals = AliceCoinTokenInfo.Decimals,
Issuer = AliceCoinTokenInfo.Issuer,
+ Owner = AliceCoinTokenInfo.Issuer,
IsBurnable = AliceCoinTokenInfo.IsBurnable,
ExternalInfo = { { "key", "value" } }
});
@@ -1239,14 +1182,6 @@ await TokenContractStub.Create.SendAsync(new CreateInput
[Fact]
public async Task CrossContractCreateToken_Test()
{
- await CreateNativeTokenAsync();
- await TokenContractStub.Issue.SendAsync(new IssueInput
- {
- Symbol = NativeToken,
- To = BasicFunctionContractAddress,
- Amount = 10000_00000000
- });
-
var fee = await TokenContractStub.GetMethodFee.CallAsync(new StringValue { Value = "Create" });
var createTokenInput = new CreateTokenThroughMultiTokenInput
{
@@ -1258,22 +1193,31 @@ await TokenContractStub.Issue.SendAsync(new IssueInput
TotalSupply = TotalSupply,
ExternalInfo = new TestContract.BasicFunction.ExternalInfo()
};
+ var input = new CreateInput
+ {
+ Symbol = SeedNFTSymbolPre + 100,
+ Decimals = 0,
+ IsBurnable = true,
+ TokenName = "seed token" + 100,
+ TotalSupply = 1,
+ Issuer = DefaultAddress,
+ ExternalInfo = new ExternalInfo(),
+ LockWhiteList = { TokenContractAddress },
+ Owner = DefaultAddress
+ };
+ input.ExternalInfo.Value["__seed_owned_symbol"] = createTokenInput.Symbol;
+ input.ExternalInfo.Value["__seed_exp_time"] = TimestampHelper.GetUtcNow().AddDays(1).Seconds.ToString();
+ await TokenContractStub.Create.SendAsync(input);
+ await TokenContractStub.Issue.SendAsync(new IssueInput
+ {
+ Symbol = input.Symbol,
+ Amount = 1,
+ Memo = "ddd",
+ To = BasicFunctionContractAddress
+ });
+
var result = await BasicFunctionContractStub.CreateTokenThroughMultiToken.SendAsync(createTokenInput);
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
-
- var logs = result.TransactionResult.Logs.First(l => l.Name.Equals("TransactionFeeCharged"));
- var transactionFeeCharged = TransactionFeeCharged.Parser.ParseFrom(logs.NonIndexed);
- transactionFeeCharged.Amount.ShouldBe(fee.Fees.First().BasicFee);
- transactionFeeCharged.Symbol.ShouldBe(fee.Fees.First().Symbol);
-
- var tokenBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
- { Owner = TokenContractAddress, Symbol = NativeToken });
- tokenBalance.Balance.ShouldBe(0);
-
- var functionBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
- { Owner = BasicFunctionContractAddress, Symbol = NativeToken });
- functionBalance.Balance.ShouldBe(0);
-
var checkTokenInfo = await TokenContractStub.GetTokenInfo.CallAsync(new GetTokenInfoInput { Symbol = "TEST" });
checkTokenInfo.Decimals.ShouldBe(createTokenInput.Decimals);
checkTokenInfo.Issuer.ShouldBe(createTokenInput.Issuer);
diff --git a/test/AElf.Contracts.MultiToken.Tests/BVT/TokenDelegationTest.cs b/test/AElf.Contracts.MultiToken.Tests/BVT/TokenDelegationTest.cs
index ad8baa382d..47acb0a625 100644
--- a/test/AElf.Contracts.MultiToken.Tests/BVT/TokenDelegationTest.cs
+++ b/test/AElf.Contracts.MultiToken.Tests/BVT/TokenDelegationTest.cs
@@ -2,7 +2,9 @@
using System.Linq;
using System.Threading.Tasks;
using AElf.Types;
+using Google.Protobuf.Collections;
using Shouldly;
+using Volo.Abp;
using Xunit;
namespace AElf.Contracts.MultiToken;
@@ -156,20 +158,20 @@ public async Task SetTokenDelegation_addNotExistToken_Test()
private async Task Initialize()
{
- await CreateBaseNativeTokenAsync();
await CreateTokenAsync(DefaultAddress, BasicFeeSymbol);
await CreateTokenAsync(DefaultAddress, SizeFeeSymbol);
}
private async Task CreateTokenAsync(Address creator, string tokenSymbol, bool isBurned = true)
{
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateMutiTokenAsync(TokenContractStub,new CreateInput
{
Symbol = tokenSymbol,
TokenName = tokenSymbol + " name",
TotalSupply = 1000_00000000,
IsBurnable = isBurned,
Issuer = creator,
+ Owner = creator,
});
}
@@ -274,6 +276,7 @@ await TokenContractStub.Create.SendAsync(new CreateInput
Decimals = NativeTokenInfo.Decimals,
Issuer = NativeTokenInfo.Issuer,
IsBurnable = NativeTokenInfo.IsBurnable,
+ Owner = NativeTokenInfo.Owner
});
}
@@ -307,4 +310,1504 @@ await TokenContractStubUser.SetTransactionFeeDelegations.SendAsync(new SetTransa
output.DelegateeAddresses[0].ShouldBe(DefaultAddress);
output.DelegateeAddresses[1].ShouldBe(User1Address);
}
+
+ [Fact]
+ public async Task SetDelegateInfos_NewDelegate_Success_Test()
+ {
+ await Initialize();
+ var delegations1 = new Dictionary
+ {
+ [NativeToken] = 1000,
+ [BasicFeeSymbol] = 500,
+ [SizeFeeSymbol] = 100
+ };
+ var delegations2 = new Dictionary
+ {
+ [NativeToken] = 100
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ Delegations =
+ {
+ delegations1
+ },
+ IsUnlimitedDelegate = false
+ };
+ var delegateInfo2 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test2",
+ Delegations =
+ {
+ delegations2
+ },
+ IsUnlimitedDelegate = false
+ };
+ var delegateInfo3 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test3",
+ Delegations =
+ {
+ delegations2
+ },
+ IsUnlimitedDelegate = true
+ };
+ var executionResult = await TokenContractStub.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateInfoList = { delegateInfo1,delegateInfo2,delegateInfo3 }
+ });
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.Delegations[NativeToken].ShouldBe(1000);
+ delegateInfoOfADelegatee.Delegations[BasicFeeSymbol].ShouldBe(500);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test2"
+ });
+ delegateInfoOfADelegatee.Delegations[NativeToken].ShouldBe(100);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test3"
+ });
+ delegateInfoOfADelegatee.Delegations.ShouldBeEmpty();
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeTrue();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var log = TransactionFeeDelegateInfoAdded.Parser.ParseFrom(executionResult.TransactionResult.Logs
+ .FirstOrDefault(i => i.Name == nameof(TransactionFeeDelegateInfoAdded))?.NonIndexed);
+ log.Delegator.ShouldBe(User1Address);
+ log.Delegatee.ShouldBe(DefaultAddress);
+ log.DelegateTransactionList.Value.Count.ShouldBe(3);
+ log.DelegateTransactionList.Value[0].ContractAddress.ShouldBe(BasicFunctionContractAddress);
+ log.DelegateTransactionList.Value[0].MethodName.ShouldBe("test1");
+ log.DelegateTransactionList.Value[1].ContractAddress.ShouldBe(BasicFunctionContractAddress);
+ log.DelegateTransactionList.Value[1].MethodName.ShouldBe("test2");
+ log.DelegateTransactionList.Value[2].ContractAddress.ShouldBe(BasicFunctionContractAddress);
+ log.DelegateTransactionList.Value[2].MethodName.ShouldBe("test3");
+ }
+
+ }
+ [Fact]
+ public async Task SetDelegateInfos_NewOrUpdateDelegate_Success_Test()
+ {
+ await SetDelegateInfos_NewDelegate_Success_Test();
+ var newDelegations = new Dictionary
+ {
+ [NativeToken] = 10,
+ [BasicFeeSymbol] = 20
+ };
+ var delegations2 = new Dictionary
+ {
+ [NativeToken] = 100,
+ [SizeFeeSymbol] = 30
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ ContractAddress = BasicContractZeroAddress,
+ MethodName = "test1",
+ Delegations =
+ {
+ newDelegations
+ },
+ IsUnlimitedDelegate = false
+ };
+ var delegateInfo2 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test2",
+ Delegations =
+ {
+ delegations2
+ },
+ IsUnlimitedDelegate = false
+ };
+ var executionResult = await TokenContractStub.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateInfoList = { delegateInfo1,delegateInfo2 }
+ });
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicContractZeroAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.Delegations[NativeToken].ShouldBe(10);
+ delegateInfoOfADelegatee.Delegations[BasicFeeSymbol].ShouldBe(20);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test2"
+ });
+ delegateInfoOfADelegatee.Delegations[NativeToken].ShouldBe(100);
+ delegateInfoOfADelegatee.Delegations[SizeFeeSymbol].ShouldBe(30);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var log = TransactionFeeDelegateInfoAdded.Parser.ParseFrom(executionResult.TransactionResult.Logs
+ .FirstOrDefault(i => i.Name == nameof(TransactionFeeDelegateInfoAdded))?.NonIndexed);
+ log.Delegator.ShouldBe(User1Address);
+ log.Delegatee.ShouldBe(DefaultAddress);
+ log.DelegateTransactionList.Value.Count.ShouldBe(1);
+ log.DelegateTransactionList.Value[0].ContractAddress.ShouldBe(BasicContractZeroAddress);
+ log.DelegateTransactionList.Value[0].MethodName.ShouldBe("test1");
+ }
+ {
+ var log = TransactionFeeDelegateInfoUpdated.Parser.ParseFrom(executionResult.TransactionResult.Logs
+ .FirstOrDefault(i => i.Name == nameof(TransactionFeeDelegateInfoUpdated))?.NonIndexed);
+ log.Delegator.ShouldBe(User1Address);
+ log.Delegatee.ShouldBe(DefaultAddress);
+ log.DelegateTransactionList.Value.Count.ShouldBe(1);
+ log.DelegateTransactionList.Value[0].ContractAddress.ShouldBe(BasicFunctionContractAddress);
+ log.DelegateTransactionList.Value[0].MethodName.ShouldBe("test2");
+ }
+
+ }
+ [Fact]
+ public async Task SetDelegateInfos_UpdateDelegate_Success_Test()
+ {
+ await SetDelegateInfos_NewOrUpdateDelegate_Success_Test();
+ var delegations1 = new Dictionary
+ {
+ [NativeToken] = 300,
+ [BasicFeeSymbol] = 200,
+ [SizeFeeSymbol] = 100
+ };
+ var delegations3 = new Dictionary
+ {
+ [NativeToken] = 100,
+ [BasicFeeSymbol] = 200,
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ Delegations =
+ {
+ delegations1
+ },
+ IsUnlimitedDelegate = false
+ };
+ var delegateInfo2 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test2",
+ IsUnlimitedDelegate = true
+ };
+ var delegateInfo3 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test3",
+ Delegations =
+ {
+ delegations3
+ },
+ IsUnlimitedDelegate = false
+ };
+ var delegateInfo4 = new DelegateInfo
+ {
+ ContractAddress = BasicContractZeroAddress,
+ MethodName = "test1",
+ IsUnlimitedDelegate = true
+ };
+ await TokenContractStub.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateInfoList = { delegateInfo1,delegateInfo2,delegateInfo3,delegateInfo4 }
+ });
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.Delegations[NativeToken].ShouldBe(300);
+ delegateInfoOfADelegatee.Delegations[BasicFeeSymbol].ShouldBe(200);
+ delegateInfoOfADelegatee.Delegations[SizeFeeSymbol].ShouldBe(100);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test2"
+ });
+ delegateInfoOfADelegatee.Delegations.ShouldBeEmpty();
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeTrue();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test3"
+ });
+ delegateInfoOfADelegatee.Delegations[NativeToken].ShouldBe(100);
+ delegateInfoOfADelegatee.Delegations[BasicFeeSymbol].ShouldBe(200);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicContractZeroAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.Delegations.ShouldBeEmpty();
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeTrue();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ }
+ [Fact]
+ public async Task SetDelegateInfos_UpdateDelegate_RemoveDelegation_Success_Test()
+ {
+ await SetDelegateInfos_NewOrUpdateDelegate_Success_Test();
+ var delegations1 = new Dictionary
+ {
+ [NativeToken] = 300,
+ [BasicFeeSymbol] = 200,
+ [SizeFeeSymbol] = -1
+ };
+ var delegations2 = new Dictionary
+ {
+ [NativeToken] = 0,
+ [SizeFeeSymbol] = 200,
+ };
+ var delegations3 = new Dictionary
+ {
+ [NativeToken] = 5,
+ [BasicFeeSymbol] = 0
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ Delegations =
+ {
+ delegations1
+ },
+ IsUnlimitedDelegate = false
+ };
+ var delegateInfo2 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test2",
+ Delegations =
+ {
+ delegations2
+ },
+ IsUnlimitedDelegate = false
+ };
+ var delegateInfo3 = new DelegateInfo
+ {
+ ContractAddress = BasicContractZeroAddress,
+ MethodName = "test1",
+ Delegations =
+ {
+ delegations3
+ },
+ IsUnlimitedDelegate = false
+ };
+ var executionResult = await TokenContractStub.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateInfoList = { delegateInfo1,delegateInfo2,delegateInfo3 }
+ });
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.Delegations.Count.ShouldBe(2);
+ delegateInfoOfADelegatee.Delegations[NativeToken].ShouldBe(300);
+ delegateInfoOfADelegatee.Delegations[BasicFeeSymbol].ShouldBe(200);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test2"
+ });
+ delegateInfoOfADelegatee.Delegations.Count.ShouldBe(1);
+ delegateInfoOfADelegatee.Delegations[SizeFeeSymbol].ShouldBe(200);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicContractZeroAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.Delegations.Count.ShouldBe(1);
+ delegateInfoOfADelegatee.Delegations[NativeToken].ShouldBe(5);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var log = TransactionFeeDelegateInfoUpdated.Parser.ParseFrom(executionResult.TransactionResult.Logs
+ .FirstOrDefault(i => i.Name == nameof(TransactionFeeDelegateInfoUpdated))?.NonIndexed);
+ log.Delegator.ShouldBe(User1Address);
+ log.Delegatee.ShouldBe(DefaultAddress);
+ log.DelegateTransactionList.Value.Count.ShouldBe(3);
+ log.DelegateTransactionList.Value[0].ContractAddress.ShouldBe(BasicFunctionContractAddress);
+ log.DelegateTransactionList.Value[0].MethodName.ShouldBe("test1");
+ log.DelegateTransactionList.Value[1].ContractAddress.ShouldBe(BasicFunctionContractAddress);
+ log.DelegateTransactionList.Value[1].MethodName.ShouldBe("test2");
+ log.DelegateTransactionList.Value[2].ContractAddress.ShouldBe(BasicContractZeroAddress);
+ log.DelegateTransactionList.Value[2].MethodName.ShouldBe("test1");
+ }
+ }
+ [Fact]
+ public async Task SetDelegateInfos_UpdateDelegate_RemoveDelegateInfo_Success_Test()
+ {
+ await SetDelegateInfos_NewDelegate_Success_Test();
+ var delegations1 = new Dictionary
+ {
+ [NativeToken] = -1,
+ [BasicFeeSymbol] = -1,
+ [SizeFeeSymbol] = -1
+ };
+ var delegations2 = new Dictionary
+ {
+ [NativeToken] = -1,
+ [BasicFeeSymbol] = 200,
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ Delegations =
+ {
+ delegations1
+ },
+ IsUnlimitedDelegate = false
+ };
+ var delegateInfo2 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test2",
+ Delegations =
+ {
+ delegations2
+ },
+ IsUnlimitedDelegate = false
+ };
+ var executionResult = await TokenContractStub.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateInfoList = { delegateInfo1,delegateInfo2 }
+ });
+ {
+ var delegateeAddress = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ MethodName = "test1"
+ });
+ delegateeAddress.DelegateeAddresses.Count.ShouldBe(0);
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.ShouldBe(new TransactionFeeDelegations());
+ }
+ {
+ var delegateeAddress = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ MethodName = "test2"
+ });
+ delegateeAddress.DelegateeAddresses.Count.ShouldBe(1);
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test2"
+ });
+ delegateInfoOfADelegatee.Delegations.Count.ShouldBe(1);
+ delegateInfoOfADelegatee.Delegations[BasicFeeSymbol].ShouldBe(200);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var log = TransactionFeeDelegateInfoCancelled.Parser.ParseFrom(executionResult.TransactionResult.Logs
+ .FirstOrDefault(i => i.Name == nameof(TransactionFeeDelegateInfoCancelled))?.NonIndexed);
+ log.Delegator.ShouldBe(User1Address);
+ log.Delegatee.ShouldBe(DefaultAddress);
+ log.DelegateTransactionList.Value.Count.ShouldBe(1);
+ log.DelegateTransactionList.Value[0].ContractAddress.ShouldBe(BasicFunctionContractAddress);
+ log.DelegateTransactionList.Value[0].MethodName.ShouldBe("test1");
+ }
+ }
+
+ [Fact]
+ public async Task SetDelegateInfos_AddOrUpdateOrRemoveDelegate_Success_Test()
+ {
+ await SetDelegateInfos_NewOrUpdateDelegate_Success_Test();
+ var delegations1 = new Dictionary
+ {
+ [NativeToken] = 300,
+ [BasicFeeSymbol] = 200,
+ [SizeFeeSymbol] = 0
+ };
+ var delegations4 = new Dictionary
+ {
+ [NativeToken] = 60,
+ };
+ var delegations5 = new Dictionary
+ {
+ [NativeToken] = 0,
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ Delegations =
+ {
+ delegations1
+ },
+ IsUnlimitedDelegate = false
+ };
+ var delegateInfo2 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test2",
+ IsUnlimitedDelegate = true
+ };
+ var delegateInfo4 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test4",
+ Delegations =
+ {
+ delegations4
+ },
+ IsUnlimitedDelegate = false
+ };
+ var delegateInfo5 = new DelegateInfo
+ {
+ ContractAddress = BasicContractZeroAddress,
+ MethodName = "test1",
+ Delegations =
+ {
+ delegations5
+ },
+ IsUnlimitedDelegate = false
+ };
+ var executionResult = await TokenContractStub.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateInfoList = { delegateInfo1,delegateInfo2,delegateInfo4,delegateInfo5 }
+ });
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.Delegations.Count.ShouldBe(2);
+ delegateInfoOfADelegatee.Delegations[NativeToken].ShouldBe(300);
+ delegateInfoOfADelegatee.Delegations[BasicFeeSymbol].ShouldBe(200);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test2"
+ });
+ delegateInfoOfADelegatee.Delegations.ShouldBeEmpty();
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeTrue();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test4"
+ });
+ delegateInfoOfADelegatee.Delegations[NativeToken].ShouldBe(60);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicContractZeroAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.Delegations.Count.ShouldBe(1);
+ delegateInfoOfADelegatee.Delegations[BasicFeeSymbol].ShouldBe(20);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ {
+ var log = TransactionFeeDelegateInfoAdded.Parser.ParseFrom(executionResult.TransactionResult.Logs
+ .FirstOrDefault(i => i.Name == nameof(TransactionFeeDelegateInfoAdded))?.NonIndexed);
+ log.Delegator.ShouldBe(User1Address);
+ log.Delegatee.ShouldBe(DefaultAddress);
+ log.DelegateTransactionList.Value.Count.ShouldBe(1);
+ log.DelegateTransactionList.Value[0].ContractAddress.ShouldBe(BasicFunctionContractAddress);
+ log.DelegateTransactionList.Value[0].MethodName.ShouldBe("test4");
+ }
+ {
+ var log = TransactionFeeDelegateInfoUpdated.Parser.ParseFrom(executionResult.TransactionResult.Logs
+ .FirstOrDefault(i => i.Name == nameof(TransactionFeeDelegateInfoUpdated))?.NonIndexed);
+ log.Delegator.ShouldBe(User1Address);
+ log.Delegatee.ShouldBe(DefaultAddress);
+ log.DelegateTransactionList.Value.Count.ShouldBe(3);
+ log.DelegateTransactionList.Value[0].ContractAddress.ShouldBe(BasicFunctionContractAddress);
+ log.DelegateTransactionList.Value[0].MethodName.ShouldBe("test1");
+ log.DelegateTransactionList.Value[1].ContractAddress.ShouldBe(BasicFunctionContractAddress);
+ log.DelegateTransactionList.Value[1].MethodName.ShouldBe("test2");
+ log.DelegateTransactionList.Value[2].ContractAddress.ShouldBe(BasicContractZeroAddress);
+ log.DelegateTransactionList.Value[2].MethodName.ShouldBe("test1");
+ }
+ }
+ }
+
+ [Fact]
+ public async Task SetDelegateInfos_MultiDelegateeAndSameTransaction_Success_Test()
+ {
+ await Initialize();
+ var delegations1 = new Dictionary
+ {
+ [NativeToken] = 1000,
+ [BasicFeeSymbol] = 500,
+ [SizeFeeSymbol] = 100
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ Delegations =
+ {
+ delegations1
+ },
+ IsUnlimitedDelegate = false
+ };
+ //Default -> User1
+ await TokenContractStub.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ //User2 -> User1
+ await TokenContractStubDelegate.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.Delegations.Count.ShouldBe(3);
+ delegateInfoOfADelegatee.Delegations[NativeToken].ShouldBe(1000);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = User2Address,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.Delegations.Count.ShouldBe(3);
+ delegateInfoOfADelegatee.Delegations[NativeToken].ShouldBe(1000);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var delegateeList = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ DelegatorAddress = User1Address
+ });
+ delegateeList.DelegateeAddresses.Count.ShouldBe(2);
+ delegateeList.DelegateeAddresses[0].ShouldBe(DefaultAddress);
+ delegateeList.DelegateeAddresses[1].ShouldBe(User2Address);
+ }
+ }
+
+ [Fact]
+ public async Task SetDelegateInfos_MultiDelegatorAndSameTransaction_Success_Test()
+ {
+ await Initialize();
+ var delegations1 = new Dictionary
+ {
+ [NativeToken] = 1000,
+ [BasicFeeSymbol] = 500,
+ [SizeFeeSymbol] = 100
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ Delegations =
+ {
+ delegations1
+ },
+ IsUnlimitedDelegate = false
+ };
+ //Default -> User1
+ await TokenContractStub.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ //Default -> User2
+ await TokenContractStub.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User2Address,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.Delegations.Count.ShouldBe(3);
+ delegateInfoOfADelegatee.Delegations[NativeToken].ShouldBe(1000);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User2Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.Delegations.Count.ShouldBe(3);
+ delegateInfoOfADelegatee.Delegations[NativeToken].ShouldBe(1000);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ {
+ var delegateeList = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ DelegatorAddress = User1Address
+ });
+ delegateeList.DelegateeAddresses.Count.ShouldBe(1);
+ delegateeList.DelegateeAddresses[0].ShouldBe(DefaultAddress);
+ }
+ {
+ var delegateeList = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ DelegatorAddress = User2Address
+ });
+ delegateeList.DelegateeAddresses.Count.ShouldBe(1);
+ delegateeList.DelegateeAddresses[0].ShouldBe(DefaultAddress);
+ }
+ }
+ [Fact]
+ public async Task SetDelegateInfos_InvalidInput_Failed_Test()
+ {
+ await Initialize();
+ var delegations1 = new Dictionary
+ {
+ [NativeToken] = 1000,
+ [BasicFeeSymbol] = 500,
+ [SizeFeeSymbol] = 100
+ };
+ var delegateInfo = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ Delegations = { delegations1 }
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ IsUnlimitedDelegate = false
+ };
+ var delegateInfo2 = new DelegateInfo
+ {
+ MethodName = "test1",
+ Delegations = { delegations1 },
+ IsUnlimitedDelegate = false
+ };
+ var delegateInfo3 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ Delegations = { delegations1 },
+ IsUnlimitedDelegate = false
+ };
+ {
+ await TokenContractStub.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateInfoList = { delegateInfo }
+ });
+ }
+ {
+ var transactionFeeDelegation = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress
+ });
+ transactionFeeDelegation.IsUnlimitedDelegate.ShouldBeFalse();
+ transactionFeeDelegation.Delegations.Count.ShouldBe(3);
+ transactionFeeDelegation.Delegations[NativeToken].ShouldBe(1000);
+ }
+ {
+ var executionResult = await TokenContractStub.SetTransactionFeeDelegateInfos.SendWithExceptionAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ executionResult.TransactionResult.Error.ShouldContain("Delegation cannot be null.");
+ }
+ {
+ var executionResult = await TokenContractStub.SetTransactionFeeDelegateInfos.SendWithExceptionAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateInfoList = { delegateInfo2 }
+ });
+ executionResult.TransactionResult.Error.ShouldContain("Invalid contract address and method name.");
+ }
+ {
+ var executionResult = await TokenContractStub.SetTransactionFeeDelegateInfos.SendWithExceptionAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateInfoList = { delegateInfo3 }
+ });
+ executionResult.TransactionResult.Error.ShouldContain("Invalid contract address and method name.");
+ }
+ {
+ var executionResult = await TokenContractStub.SetTransactionFeeDelegateInfos.SendWithExceptionAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegateInfoList = { delegateInfo }
+ });
+ executionResult.TransactionResult.Error.ShouldContain("Delegator address and delegate info cannot be null.");
+ }
+ {
+ var executionResult = await TokenContractStub.SetTransactionFeeDelegateInfos.SendWithExceptionAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ });
+ executionResult.TransactionResult.Error.ShouldContain("Delegator address and delegate info cannot be null.");
+ }
+ }
+
+ [Fact]
+ public async Task RemoveTransactionFeeDelegateeInfos_Success_Test()
+ {
+ await SetDelegateInfos_NewDelegate_Success_Test();
+ var delegations1 = new Dictionary
+ {
+ [NativeToken] = 300,
+ [BasicFeeSymbol] = 200
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ Delegations =
+ {
+ delegations1
+ },
+ IsUnlimitedDelegate = false
+ };
+ await TokenContractStubDelegate.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.Delegations[NativeToken].ShouldBe(1000);
+ delegateInfoOfADelegatee.Delegations[BasicFeeSymbol].ShouldBe(500);
+ delegateInfoOfADelegatee.IsUnlimitedDelegate.ShouldBeFalse();
+ delegateInfoOfADelegatee.BlockHeight.ShouldBeGreaterThan(0);
+ }
+ var delegationTransactionList = new RepeatedField
+ {
+ new DelegateTransaction
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1"
+ },
+ new DelegateTransaction
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test3"
+ }
+ };
+ await TokenContractStubUser.RemoveTransactionFeeDelegateeInfos.SendAsync(new RemoveTransactionFeeDelegateeInfosInput
+ {
+ DelegateeAddress = DefaultAddress,
+ DelegateTransactionList = { delegationTransactionList }
+ });
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.ShouldBe(new TransactionFeeDelegations());
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test2"
+ });
+ delegateInfoOfADelegatee.Delegations[NativeToken] = 100;
+ delegateInfoOfADelegatee.IsUnlimitedDelegate = false;
+ }
+ {
+ var delegateeAddress = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ MethodName = "test1"
+ });
+ delegateeAddress.DelegateeAddresses.Count.ShouldBe(1);
+ delegateeAddress.DelegateeAddresses[0].ShouldBe(User2Address);
+ }
+ }
+
+ [Fact]
+ public async Task RemoveTransactionFeeDelegateeInfos_SingleTransaction_Success_Test()
+ {
+ await SetDelegateInfos_NewDelegate_Success_Test();
+ var delegationTransactionList = new RepeatedField
+ {
+ new DelegateTransaction
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1"
+ }
+ };
+ var executionResult = await TokenContractStubUser.RemoveTransactionFeeDelegateeInfos.SendAsync(new RemoveTransactionFeeDelegateeInfosInput
+ {
+ DelegateeAddress = DefaultAddress,
+ DelegateTransactionList = { delegationTransactionList }
+ });
+ {
+ var transactionDelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress
+ });
+ transactionDelegatee.ShouldBe(new TransactionFeeDelegations());
+ }
+ {
+ var delegateeList = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ DelegatorAddress = User1Address,
+ });
+ delegateeList.DelegateeAddresses.Count.ShouldBe(0);
+ }
+ {
+ var log = TransactionFeeDelegateInfoCancelled.Parser.ParseFrom(executionResult.TransactionResult.Logs
+ .FirstOrDefault(i => i.Name == nameof(TransactionFeeDelegateInfoCancelled))?.NonIndexed);
+ log.Delegatee.ShouldBe(DefaultAddress);
+ log.Delegator.ShouldBe(User1Address);
+ delegationTransactionList.Count.ShouldBe(1);
+ delegationTransactionList[0].ContractAddress.ShouldBe(BasicFunctionContractAddress);
+ delegationTransactionList[0].MethodName.ShouldBe("test1");
+ }
+ }
+ [Fact]
+ public async Task RemoveTransactionFeeDelegateeInfos_MultiTransaction_Success_Test()
+ {
+ await SetDelegateInfos_NewOrUpdateDelegate_Success_Test();
+ var delegationTransactionList = new RepeatedField
+ {
+ new DelegateTransaction
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1"
+ },
+ new DelegateTransaction
+ {
+ ContractAddress = BasicContractZeroAddress,
+ MethodName = "test1"
+ }
+ };
+ var executionResult = await TokenContractStubUser.RemoveTransactionFeeDelegateeInfos.SendAsync(new RemoveTransactionFeeDelegateeInfosInput
+ {
+ DelegateeAddress = DefaultAddress,
+ DelegateTransactionList = { delegationTransactionList }
+ });
+ {
+ var transactionDelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress
+ });
+ transactionDelegatee.ShouldBe(new TransactionFeeDelegations());
+ }
+ {
+ var transactionDelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicContractZeroAddress,
+ MethodName = "test1",
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress
+ });
+ transactionDelegatee.ShouldBe(new TransactionFeeDelegations());
+ }
+ {
+ var delegateeList = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ DelegatorAddress = User1Address,
+ });
+ delegateeList.DelegateeAddresses.Count.ShouldBe(0);
+ }
+ {
+ var delegateeList = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = BasicContractZeroAddress,
+ MethodName = "test1",
+ DelegatorAddress = User1Address,
+ });
+ delegateeList.DelegateeAddresses.Count.ShouldBe(0);
+ }
+ {
+ var log = TransactionFeeDelegateInfoCancelled.Parser.ParseFrom(executionResult.TransactionResult.Logs
+ .FirstOrDefault(i => i.Name == nameof(TransactionFeeDelegateInfoCancelled))?.NonIndexed);
+ log.Delegatee.ShouldBe(DefaultAddress);
+ log.Delegator.ShouldBe(User1Address);
+ delegationTransactionList.Count.ShouldBe(2);
+ delegationTransactionList[0].ContractAddress.ShouldBe(BasicFunctionContractAddress);
+ delegationTransactionList[0].MethodName.ShouldBe("test1");
+ delegationTransactionList[1].ContractAddress.ShouldBe(BasicContractZeroAddress);
+ delegationTransactionList[1].MethodName.ShouldBe("test1");
+ }
+ }
+ [Fact]
+ public async Task RemoveTransactionFeeDelegateeInfos_NotExistTransaction_Success_Test()
+ {
+ await SetDelegateInfos_NewOrUpdateDelegate_Success_Test();
+ var delegationTransactionList = new RepeatedField
+ {
+ new DelegateTransaction
+ {
+ ContractAddress = TokenContractAddress,
+ MethodName = "transfer"
+ }
+ };
+ var executionResult = await TokenContractStubUser.RemoveTransactionFeeDelegateeInfos.SendAsync(new RemoveTransactionFeeDelegateeInfosInput
+ {
+ DelegateeAddress = DefaultAddress,
+ DelegateTransactionList = { delegationTransactionList }
+ });
+ var executionResult1 = await TokenContractStubUser.RemoveTransactionFeeDelegateeInfos.SendAsync(new RemoveTransactionFeeDelegateeInfosInput
+ {
+ DelegateeAddress = User2Address,
+ DelegateTransactionList = { delegationTransactionList }
+ });
+ {
+ var transactionDelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = TokenContractAddress,
+ MethodName = "transfer",
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress
+ });
+ transactionDelegatee.ShouldBe(new TransactionFeeDelegations());
+ }
+ {
+ var delegateeList = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = TokenContractAddress,
+ MethodName = "transfer",
+ DelegatorAddress = User1Address,
+ });
+ delegateeList.DelegateeAddresses.Count.ShouldBe(0);
+ }
+ {
+ var transactionDelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = TokenContractAddress,
+ MethodName = "transfer",
+ DelegatorAddress = User1Address,
+ DelegateeAddress = User2Address
+ });
+ transactionDelegatee.ShouldBe(new TransactionFeeDelegations());
+ }
+ {
+ var delegateeList = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = TokenContractAddress,
+ MethodName = "transfer",
+ DelegatorAddress = User1Address,
+ });
+ delegateeList.DelegateeAddresses.Count.ShouldBe(0);
+ }
+ }
+
+ [Fact]
+ public async Task RemoveTransactionFeeDelegateeInfos_InvalidInput_Failed_Test()
+ {
+ await SetDelegateInfos_NewOrUpdateDelegate_Success_Test();
+ var delegationTransactionList = new RepeatedField
+ {
+ new DelegateTransaction
+ {
+ ContractAddress = BasicContractZeroAddress
+ },
+ new DelegateTransaction
+ {
+ MethodName = "jsh&&&"
+ },
+ new DelegateTransaction
+ {
+
+ }
+ };
+ var executionResult = await TokenContractStubUser.RemoveTransactionFeeDelegateeInfos.SendWithExceptionAsync(new RemoveTransactionFeeDelegateeInfosInput
+ {
+ DelegateeAddress = DefaultAddress,
+ DelegateTransactionList = { delegationTransactionList }
+ });
+ executionResult.TransactionResult.Error.ShouldContain("Invalid contract address and method name.");
+ }
+ [Fact]
+ public async Task RemoveTransactionFeeDelegatorInfos_Success_Test()
+ {
+ await SetDelegateInfos_NewDelegate_Success_Test();
+ var delegations1 = new Dictionary
+ {
+ [NativeToken] = 300,
+ [BasicFeeSymbol] = 200
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ Delegations =
+ {
+ delegations1
+ },
+ IsUnlimitedDelegate = false
+ };
+ await TokenContractStub.SetTransactionFeeDelegateInfos.SendAsync(new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = User2Address,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ var delegationTransactionList = new RepeatedField
+ {
+ new DelegateTransaction
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1"
+ },
+ new DelegateTransaction
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test3"
+ }
+ };
+ await TokenContractStub.RemoveTransactionFeeDelegatorInfos.SendAsync(new RemoveTransactionFeeDelegatorInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateTransactionList = { delegationTransactionList }
+ });
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test1"
+ });
+ delegateInfoOfADelegatee.ShouldBe(new TransactionFeeDelegations());
+ }
+ {
+ var delegateInfoOfADelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress,
+ MethodName = "test2"
+ });
+ delegateInfoOfADelegatee.Delegations[NativeToken] = 100;
+ delegateInfoOfADelegatee.IsUnlimitedDelegate = false;
+ }
+ {
+ var delegateeAddress = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ DelegatorAddress = User2Address,
+ MethodName = "test1"
+ });
+ delegateeAddress.DelegateeAddresses.Count.ShouldBe(1);
+ delegateeAddress.DelegateeAddresses[0].ShouldBe(DefaultAddress);
+ }
+ }
+ [Fact]
+ public async Task RemoveTransactionFeeDelegatorInfos_SingleTransaction_Success_Test()
+ {
+ await SetDelegateInfos_NewDelegate_Success_Test();
+ var delegationTransactionList = new RepeatedField
+ {
+ new DelegateTransaction
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1"
+ }
+ };
+ var executionResult = await TokenContractStub.RemoveTransactionFeeDelegatorInfos.SendAsync(new RemoveTransactionFeeDelegatorInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateTransactionList = { delegationTransactionList }
+ });
+ {
+ var transactionDelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress
+ });
+ transactionDelegatee.ShouldBe(new TransactionFeeDelegations());
+ }
+ {
+ var delegateeList = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ DelegatorAddress = User1Address,
+ });
+ delegateeList.DelegateeAddresses.Count.ShouldBe(0);
+ }
+ {
+ var log = TransactionFeeDelegateInfoCancelled.Parser.ParseFrom(executionResult.TransactionResult.Logs
+ .FirstOrDefault(i => i.Name == nameof(TransactionFeeDelegateInfoCancelled))?.NonIndexed);
+ log.Delegatee.ShouldBe(DefaultAddress);
+ log.Delegator.ShouldBe(User1Address);
+ delegationTransactionList.Count.ShouldBe(1);
+ delegationTransactionList[0].ContractAddress.ShouldBe(BasicFunctionContractAddress);
+ delegationTransactionList[0].MethodName.ShouldBe("test1");
+ }
+ }
+ [Fact]
+ public async Task RemoveTransactionFeeDelegatorInfos_MultiTransaction_Success_Test()
+ {
+ await SetDelegateInfos_NewOrUpdateDelegate_Success_Test();
+ var delegationTransactionList = new RepeatedField
+ {
+ new DelegateTransaction
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1"
+ },
+ new DelegateTransaction
+ {
+ ContractAddress = BasicContractZeroAddress,
+ MethodName = "test1"
+ }
+ };
+ var executionResult = await TokenContractStub.RemoveTransactionFeeDelegatorInfos.SendAsync(new RemoveTransactionFeeDelegatorInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateTransactionList = { delegationTransactionList }
+ });
+ {
+ var transactionDelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress
+ });
+ transactionDelegatee.ShouldBe(new TransactionFeeDelegations());
+ }
+ {
+ var transactionDelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = BasicContractZeroAddress,
+ MethodName = "test1",
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress
+ });
+ transactionDelegatee.ShouldBe(new TransactionFeeDelegations());
+ }
+ {
+ var delegateeList = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = BasicFunctionContractAddress,
+ MethodName = "test1",
+ DelegatorAddress = User1Address,
+ });
+ delegateeList.DelegateeAddresses.Count.ShouldBe(0);
+ }
+ {
+ var delegateeList = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = BasicContractZeroAddress,
+ MethodName = "test1",
+ DelegatorAddress = User1Address,
+ });
+ delegateeList.DelegateeAddresses.Count.ShouldBe(0);
+ }
+ {
+ var log = TransactionFeeDelegateInfoCancelled.Parser.ParseFrom(executionResult.TransactionResult.Logs
+ .FirstOrDefault(i => i.Name == nameof(TransactionFeeDelegateInfoCancelled))?.NonIndexed);
+ log.Delegatee.ShouldBe(DefaultAddress);
+ log.Delegator.ShouldBe(User1Address);
+ delegationTransactionList.Count.ShouldBe(2);
+ delegationTransactionList[0].ContractAddress.ShouldBe(BasicFunctionContractAddress);
+ delegationTransactionList[0].MethodName.ShouldBe("test1");
+ delegationTransactionList[1].ContractAddress.ShouldBe(BasicContractZeroAddress);
+ delegationTransactionList[1].MethodName.ShouldBe("test1");
+ }
+ }
+ [Fact]
+ public async Task RemoveTransactionFeeDelegatorInfos_NotExistTransaction_Success_Test()
+ {
+ await SetDelegateInfos_NewOrUpdateDelegate_Success_Test();
+ var delegationTransactionList = new RepeatedField
+ {
+ new DelegateTransaction
+ {
+ ContractAddress = TokenContractAddress,
+ MethodName = "transfer"
+ }
+ };
+ var executionResult = await TokenContractStub.RemoveTransactionFeeDelegatorInfos.SendAsync(new RemoveTransactionFeeDelegatorInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateTransactionList = { delegationTransactionList }
+ });
+ var executionResult1 = await TokenContractStub.RemoveTransactionFeeDelegatorInfos.SendAsync(new RemoveTransactionFeeDelegatorInfosInput
+ {
+ DelegatorAddress = User2Address,
+ DelegateTransactionList = { delegationTransactionList }
+ });
+ {
+ var transactionDelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = TokenContractAddress,
+ MethodName = "transfer",
+ DelegatorAddress = User1Address,
+ DelegateeAddress = DefaultAddress
+ });
+ transactionDelegatee.ShouldBe(new TransactionFeeDelegations());
+ }
+ {
+ var delegateeList = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = TokenContractAddress,
+ MethodName = "transfer",
+ DelegatorAddress = User1Address,
+ });
+ delegateeList.DelegateeAddresses.Count.ShouldBe(0);
+ }
+ {
+ var transactionDelegatee = await TokenContractStub.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ ContractAddress = TokenContractAddress,
+ MethodName = "transfer",
+ DelegatorAddress = User2Address,
+ DelegateeAddress = DefaultAddress
+ });
+ transactionDelegatee.ShouldBe(new TransactionFeeDelegations());
+ }
+ {
+ var delegateeList = await TokenContractStub.GetTransactionFeeDelegateeList.CallAsync(
+ new GetTransactionFeeDelegateeListInput
+ {
+ ContractAddress = TokenContractAddress,
+ MethodName = "transfer",
+ DelegatorAddress = User2Address,
+ });
+ delegateeList.DelegateeAddresses.Count.ShouldBe(0);
+ }
+ }
+
+ [Fact]
+ public async Task RemoveTransactionFeeDelegatorInfos_InvalidInput_Failed_Test()
+ {
+ await SetDelegateInfos_NewOrUpdateDelegate_Success_Test();
+ var delegationTransactionList = new RepeatedField
+ {
+ new DelegateTransaction
+ {
+ ContractAddress = BasicContractZeroAddress
+ },
+ new DelegateTransaction
+ {
+ MethodName = "jsh&&&"
+ },
+ new DelegateTransaction
+ {
+
+ }
+ };
+ var executionResult = await TokenContractStub.RemoveTransactionFeeDelegatorInfos.SendWithExceptionAsync(new RemoveTransactionFeeDelegatorInfosInput
+ {
+ DelegatorAddress = User1Address,
+ DelegateTransactionList = { delegationTransactionList }
+ });
+ executionResult.TransactionResult.Error.ShouldContain("Invalid contract address and method name.");
+ }
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.MultiToken.Tests/BVT/TokenEconomicTests.cs b/test/AElf.Contracts.MultiToken.Tests/BVT/TokenEconomicTests.cs
index d35af8163a..89ab1cce32 100644
--- a/test/AElf.Contracts.MultiToken.Tests/BVT/TokenEconomicTests.cs
+++ b/test/AElf.Contracts.MultiToken.Tests/BVT/TokenEconomicTests.cs
@@ -18,7 +18,8 @@ await TokenContractStub.Create.SendAsync(new CreateInput
TokenName = "elf token",
TotalSupply = totalSupply,
Issuer = DefaultAddress,
- LockWhiteList = { TreasuryContractAddress }
+ LockWhiteList = { TreasuryContractAddress },
+ Owner = DefaultAddress
});
await TokenContractStub.Issue.SendAsync(new IssueInput
{
@@ -51,7 +52,8 @@ await TreasuryContractStub.InitialMiningRewardProfitItem.SendAsync(
{
ParliamentContractAddress,
TreasuryContractAddress
- }
+ },
+ Owner = DefaultAddress
})).TransactionResult;
}
diff --git a/test/AElf.Contracts.MultiToken.Tests/BVT/TokenFeeTest.cs b/test/AElf.Contracts.MultiToken.Tests/BVT/TokenFeeTest.cs
index 05cdb0efab..c4ae34ae8f 100644
--- a/test/AElf.Contracts.MultiToken.Tests/BVT/TokenFeeTest.cs
+++ b/test/AElf.Contracts.MultiToken.Tests/BVT/TokenFeeTest.cs
@@ -1,5 +1,6 @@
using System.Linq;
using System.Threading.Tasks;
+using AElf.CSharp.Core;
using AElf.Types;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
@@ -13,7 +14,7 @@ public partial class MultiTokenContractTests
[Fact(DisplayName = "[MultiToken] advance token not exist in resource token")]
public async Task AdvancedResourceToken_Test()
{
- await CreateNativeTokenAsync();
+ // await CreateNativeTokenAsync();
long advanceAmount = 1000;
{
var tokenNotResrouce = "NORESOURCE";
@@ -51,7 +52,6 @@ public async Task AdvancedResourceToken_Test()
[Fact(DisplayName = "[MultiToken] take more token than that of the contract address's balance")]
public async Task TakeResourceTokenBack_Test()
{
- await CreateNativeTokenAsync();
var trafficToken = "TRAFFIC";
var advanceAmount = 1000;
await CreateAndIssueCustomizeTokenAsync(DefaultAddress, trafficToken, 10000, 10000);
@@ -134,7 +134,13 @@ public async Task UpdateCoefficientForSender_Without_Authorization_Test()
initializeControllerRet.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
var updateRet =
await TokenContractStub.UpdateCoefficientsForSender.SendWithExceptionAsync(
- new UpdateCoefficientsInput());
+ new UpdateCoefficientsInput
+ {
+ Coefficients = new CalculateFeeCoefficients
+ {
+ FeeTokenType = 0
+ }
+ });
updateRet.TransactionResult.Error.ShouldContain("no permission");
}
@@ -166,11 +172,11 @@ public async Task InitializeAuthorizedController_Test()
}
[Fact(DisplayName = "[MultiToken] illegal controller try to set free allowances")]
- public async Task ConfigMethodFeeFreeAllowances_Without_Authorization_Test()
+ public async Task ConfigTransactionFeeFreeAllowances_Without_Authorization_Test()
{
- var configMethodFeeFreeAllowancesRet =
- await TokenContractStub.ConfigMethodFeeFreeAllowances.SendWithExceptionAsync(new MethodFeeFreeAllowancesConfig());
- configMethodFeeFreeAllowancesRet.TransactionResult.Error.ShouldContain("Unauthorized behavior.");
+ var configTransactionFeeFreeAllowancesRet =
+ await TokenContractStub.ConfigTransactionFeeFreeAllowances.SendWithExceptionAsync(new ConfigTransactionFeeFreeAllowancesInput());
+ configTransactionFeeFreeAllowancesRet.TransactionResult.Error.ShouldContain("Unauthorized behavior.");
}
[Fact]
@@ -222,7 +228,7 @@ private async Task SubmitAndApproveProposalOfDefaultParliament(Address contractA
{
var defaultParliamentAddress =
await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
- var proposalId = await CreateProposalAsync(TokenContractAddress,
+ var proposalId = await CreateProposalAsync(contractAddress,
defaultParliamentAddress, methodName, message);
await ApproveWithMinersAsync(proposalId);
var releaseResult = await ParliamentContractStub.Release.SendAsync(proposalId);
@@ -230,6 +236,19 @@ private async Task SubmitAndApproveProposalOfDefaultParliament(Address contractA
releaseResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
}
+ private async Task> SubmitAndApproveProposalOfDefaultParliamentWithException(
+ Address contractAddress,
+ string methodName,
+ IMessage message)
+ {
+ var defaultParliamentAddress =
+ await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
+ var proposalId = await CreateProposalAsync(contractAddress,
+ defaultParliamentAddress, methodName, message);
+ await ApproveWithMinersAsync(proposalId);
+ return await ParliamentContractStub.Release.SendWithExceptionAsync(proposalId);
+ }
+
private Transaction GenerateTokenTransaction(Address from, string method, IMessage input)
{
return new Transaction
diff --git a/test/AElf.Contracts.MultiToken.Tests/BVT/TokenManagementTests.cs b/test/AElf.Contracts.MultiToken.Tests/BVT/TokenManagementTests.cs
index b132b14184..ae7e336a98 100644
--- a/test/AElf.Contracts.MultiToken.Tests/BVT/TokenManagementTests.cs
+++ b/test/AElf.Contracts.MultiToken.Tests/BVT/TokenManagementTests.cs
@@ -50,7 +50,8 @@ public MultiTokenContractTests()
IsBurnable = true,
Issuer = Accounts[0].Address,
Supply = 0,
- IssueChainId = _chainId
+ IssueChainId = _chainId,
+ Owner = Accounts[0].Address
};
private TokenInfo PrimaryTokenInfo => new()
@@ -78,7 +79,8 @@ public MultiTokenContractTests()
Issuer = Accounts[0].Address,
Supply = 0,
IssueChainId = _chainId,
- ExternalInfo = new ExternalInfo()
+ ExternalInfo = new ExternalInfo(),
+ Owner = Accounts[0].Address
};
///
@@ -111,7 +113,7 @@ public MultiTokenContractTests()
private async Task CreateNativeTokenAsync()
{
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateMutiTokenAsync(TokenContractStub, new CreateInput
{
Symbol = NativeTokenInfo.Symbol,
TokenName = NativeTokenInfo.TokenName,
@@ -130,21 +132,12 @@ await TokenContractStub.Create.SendAsync(new CreateInput
private async Task CreatePrimaryTokenAsync()
{
- await TokenContractStub.Create.SendAsync(new CreateInput
- {
- Symbol = NativeTokenInfo.Symbol,
- TokenName = NativeTokenInfo.TokenName,
- TotalSupply = NativeTokenInfo.TotalSupply,
- Decimals = NativeTokenInfo.Decimals,
- Issuer = NativeTokenInfo.Issuer,
- IsBurnable = NativeTokenInfo.IsBurnable
- });
-
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateMutiTokenAsync(TokenContractStub, new CreateInput
{
Decimals = PrimaryTokenInfo.Decimals,
IsBurnable = PrimaryTokenInfo.IsBurnable,
Issuer = PrimaryTokenInfo.Issuer,
+ Owner = PrimaryTokenInfo.Issuer,
TotalSupply = PrimaryTokenInfo.TotalSupply,
Symbol = PrimaryTokenInfo.Symbol,
TokenName = PrimaryTokenInfo.TokenName,
@@ -169,13 +162,14 @@ private async Task CreateNormalTokenAsync()
tokenInfo.ShouldBe(new TokenInfo());
}
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateMutiTokenAsync(TokenContractStub, new CreateInput
{
Symbol = AliceCoinTokenInfo.Symbol,
TokenName = AliceCoinTokenInfo.TokenName,
TotalSupply = AliceCoinTokenInfo.TotalSupply,
Decimals = AliceCoinTokenInfo.Decimals,
Issuer = AliceCoinTokenInfo.Issuer,
+ Owner = AliceCoinTokenInfo.Issuer,
IsBurnable = AliceCoinTokenInfo.IsBurnable,
LockWhiteList =
{
@@ -236,13 +230,14 @@ public async Task MultiTokenContract_Create_NotSame_Test()
{
await CreateAndIssueMultiTokensAsync();
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateMutiTokenAsync(TokenContractStub, new CreateInput
{
Symbol = BobCoinTokenInfo.Symbol,
TokenName = BobCoinTokenInfo.TokenName,
TotalSupply = BobCoinTokenInfo.TotalSupply,
Decimals = BobCoinTokenInfo.Decimals,
Issuer = BobCoinTokenInfo.Issuer,
+ Owner = BobCoinTokenInfo.Issuer,
IsBurnable = BobCoinTokenInfo.IsBurnable
});
@@ -259,13 +254,14 @@ await TokenContractStub.Create.SendAsync(new CreateInput
[Fact(DisplayName = "[MultiToken] Create Token use custom address")]
public async Task MultiTokenContract_Create_UseCustomAddress_Test()
{
- var transactionResult = (await TokenContractStub.Create.SendWithExceptionAsync(new CreateInput
+ var transactionResult = (await CreateMutiTokenWithExceptionAsync(TokenContractStub, new CreateInput
{
- Symbol = NativeTokenInfo.Symbol,
+ Symbol = BobCoinTokenInfo.Symbol,
Decimals = 2,
IsBurnable = true,
Issuer = DefaultAddress,
- TokenName = NativeTokenInfo.TokenName,
+ Owner = DefaultAddress,
+ TokenName = BobCoinTokenInfo.TokenName,
TotalSupply = AliceCoinTotalAmount,
LockWhiteList =
{
@@ -278,7 +274,6 @@ public async Task MultiTokenContract_Create_UseCustomAddress_Test()
private async Task CreateAndIssueMultiTokensAsync()
{
- await CreateNativeTokenAsync();
await CreateNormalTokenAsync();
//issue AliceToken amount of 1000_00L to DefaultAddress
{
@@ -299,25 +294,6 @@ private async Task CreateAndIssueMultiTokensAsync()
balance.ShouldBe(AliceCoinTotalAmount);
}
- //issue ELF amount of 1000_00L to DefaultAddress
- {
- var result = await TokenContractStub.Issue.SendAsync(new IssueInput
- {
- Symbol = "ELF",
- Amount = AliceCoinTotalAmount,
- To = DefaultAddress,
- Memo = "first issue token."
- });
- result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
-
- var balance = (await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
- {
- Owner = DefaultAddress,
- Symbol = "ELF"
- })).Balance;
- balance.ShouldBe(AliceCoinTotalAmount);
- }
-
//issue AliceToken amount of 1000L to User1Address
{
var result = await TokenContractStub.Issue.SendAsync(new IssueInput
@@ -375,7 +351,6 @@ public async Task MultiTokenContract_Issue_OutOfAmount_Test()
[Fact]
public async Task IssueToken_With_Invalid_Input()
{
- await CreateNativeTokenAsync();
await CreateNormalTokenAsync();
// to is null
{
@@ -420,11 +395,12 @@ public async Task IssueToken_With_Invalid_Input()
//invalid chain id
{
var chainTokenSymbol = "CHAIN";
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateMutiTokenAsync(TokenContractStub, new CreateInput
{
Symbol = chainTokenSymbol,
TokenName = "chain token",
Issuer = DefaultAddress,
+ Owner = DefaultAddress,
IssueChainId = 10,
TotalSupply = 1000_000,
Decimals = 8
@@ -443,13 +419,13 @@ await TokenContractStub.Create.SendAsync(new CreateInput
[Fact]
public async Task IssueToken_Test()
{
- await CreateNativeTokenAsync();
var newTokenSymbol = "AIN";
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateMutiTokenAsync(TokenContractStub, new CreateInput
{
Symbol = newTokenSymbol,
TokenName = "ain token",
Issuer = DefaultAddress,
+ Owner = DefaultAddress,
TotalSupply = 1000_000,
Decimals = 8
});
@@ -512,21 +488,20 @@ public async Task TokenCreate_Test()
OtherBasicFunctionContractAddress,
TokenConverterContractAddress,
TreasuryContractAddress
- }
+ },
+ Owner = AliceCoinTokenInfo.Owner
};
- var createTokenRet = await TokenContractStub.Create.SendWithExceptionAsync(createTokenInfo);
- createTokenRet.TransactionResult.Error.ShouldContain("Invalid native token input");
var createTokenInfoWithInvalidTokenName = new CreateInput();
createTokenInfoWithInvalidTokenName.MergeFrom(createTokenInfo);
createTokenInfoWithInvalidTokenName.Symbol = "ITISAVERYLONGSYMBOLNAME";
- createTokenRet = await TokenContractStub.Create.SendWithExceptionAsync(createTokenInfoWithInvalidTokenName);
+ var createTokenRet =
+ await CreateSeedNftWithExceptionAsync(TokenContractStub, createTokenInfoWithInvalidTokenName);
createTokenRet.TransactionResult.Error.ShouldContain("Invalid token symbol length");
var createTokenInfoWithInvalidDecimal = new CreateInput();
createTokenInfoWithInvalidDecimal.MergeFrom(createTokenInfo);
createTokenInfoWithInvalidDecimal.Decimals = 100;
- createTokenRet = await TokenContractStub.Create.SendWithExceptionAsync(createTokenInfoWithInvalidDecimal);
+ createTokenRet = await CreateMutiTokenWithExceptionAsync(TokenContractStub, createTokenInfoWithInvalidDecimal);
createTokenRet.TransactionResult.Error.ShouldContain("Invalid input");
- await CreateNativeTokenAsync();
await TokenContractStub.Create.SendAsync(createTokenInfo);
var tokenInfo = await TokenContractStub.GetTokenInfo.CallAsync(new GetTokenInfoInput
{
@@ -544,7 +519,6 @@ public async Task SetPrimaryToken_Test()
Symbol = "NOTEXISTED"
});
setPrimaryTokenRet.TransactionResult.Error.ShouldContain("Invalid input");
- await CreateNativeTokenAsync();
await TokenContractStub.SetPrimaryTokenSymbol.SendAsync(new SetPrimaryTokenSymbolInput
{
Symbol = NativeTokenInfo.Symbol
@@ -562,7 +536,6 @@ await TokenContractStub.SetPrimaryTokenSymbol.SendAsync(new SetPrimaryTokenSymbo
[Fact]
public async Task GetNativeToken_Test()
{
- await CreateNativeTokenAsync();
var tokenInfo = await TokenContractStub.GetNativeTokenInfo.CallAsync(new Empty());
tokenInfo.Symbol.ShouldBe(NativeTokenInfo.Symbol);
}
diff --git a/test/AElf.Contracts.MultiToken.Tests/MultiTokenContractTestBase.cs b/test/AElf.Contracts.MultiToken.Tests/MultiTokenContractTestBase.cs
index 819e5f825d..232a5f5b8b 100644
--- a/test/AElf.Contracts.MultiToken.Tests/MultiTokenContractTestBase.cs
+++ b/test/AElf.Contracts.MultiToken.Tests/MultiTokenContractTestBase.cs
@@ -1,13 +1,22 @@
using System.Collections.Generic;
using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
using AElf.Contracts.Parliament;
using AElf.Contracts.TestContract.BasicFunction;
using AElf.Contracts.TokenConverter;
using AElf.Contracts.Treasury;
using AElf.ContractTestBase.ContractTestKit;
using AElf.Cryptography.ECDSA;
+using AElf.CSharp.Core;
+using AElf.CSharp.Core.Extension;
+using AElf.Kernel;
using AElf.Standards.ACS2;
+using AElf.Standards.ACS3;
using AElf.Types;
+using Google.Protobuf;
+using Google.Protobuf.WellKnownTypes;
+using Volo.Abp.Threading;
namespace AElf.Contracts.MultiToken;
@@ -15,8 +24,6 @@ public class MultiTokenContractTestBase : ContractTestBase(TokenContractAddress, DefaultKeyPair);
- TokenContractStubUser =
+
+ TokenContractStubUser =
GetTester(TokenContractAddress, User1KeyPair);
+ TokenContractStubDelegate =
+ GetTester(TokenContractAddress, User2KeyPair);
+ TokenContractStubDelegate2 =
+ GetTester(TokenContractAddress, User3KeyPair);
+ TokenContractStubDelegate3 =
+ GetTester(TokenContractAddress, User4KeyPair);
Acs2BaseStub = GetTester(TokenContractAddress, DefaultKeyPair);
TreasuryContractStub = GetTester(
@@ -54,6 +73,20 @@ public MultiTokenContractTestBase()
ParliamentContractStub = GetTester(
ParliamentContractAddress, DefaultKeyPair);
+ AsyncHelper.RunSync(() => SubmitAndApproveProposalOfDefaultParliament(TokenContractAddress,
+ nameof(TokenContractStub.Create), new CreateInput()
+ {
+ Symbol = "ELF",
+ Decimals = 8,
+ IsBurnable = true,
+ TokenName = "ELF2",
+ TotalSupply = 100_000_000_000_000_000L,
+ Issuer = DefaultAddress,
+ ExternalInfo = new ExternalInfo(),
+ Owner = DefaultAddress
+ }));
+
+ AsyncHelper.RunSync(() => CreateSeedNftCollection(TokenContractStub));
}
protected long AliceCoinTotalAmount => 1_000_000_000_0000000L;
@@ -62,7 +95,15 @@ public MultiTokenContractTestBase()
protected Address DefaultAddress => Accounts[0].Address;
protected ECKeyPair User1KeyPair => Accounts[10].KeyPair;
protected Address User1Address => Accounts[10].Address;
+ protected ECKeyPair User2KeyPair => Accounts[11].KeyPair;
protected Address User2Address => Accounts[11].Address;
+ protected ECKeyPair User3KeyPair => Accounts[12].KeyPair;
+ protected Address User3Address => Accounts[12].Address;
+ protected ECKeyPair User4KeyPair => Accounts[13].KeyPair;
+ protected Address User4Address => Accounts[13].Address;
+
+ protected int SeedNum = 0;
+ protected string SeedNFTSymbolPre = "SEED-";
protected List InitialCoreDataCenterKeyPairs =>
Accounts.Take(InitialCoreDataCenterCount).Select(a => a.KeyPair).ToList();
@@ -74,6 +115,7 @@ public MultiTokenContractTestBase()
protected Hash OtherBasicFunctionContractName =>
HashHelper.ComputeFrom("AElf.TestContractNames.OtherBasicFunction");
+
protected Address OtherBasicFunctionContractAddress { get; set; }
internal BasicFunctionContractContainer.BasicFunctionContractStub OtherBasicFunctionContractStub { get; set; }
@@ -83,4 +125,119 @@ internal ParliamentContractImplContainer.ParliamentContractImplStub GetParliamen
return GetTester(ParliamentContractAddress,
keyPair);
}
+
+ private async Task SubmitAndApproveProposalOfDefaultParliament(Address contractAddress, string methodName,
+ IMessage message)
+ {
+ var defaultParliamentAddress =
+ await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
+ var proposalId = await CreateProposalAsync(TokenContractAddress,
+ defaultParliamentAddress, methodName, message);
+ await ApproveWithMinersAsync(proposalId);
+ var releaseResult = await ParliamentContractStub.Release.SendAsync(proposalId);
+ }
+
+ private async Task CreateProposalAsync(Address contractAddress, Address organizationAddress,
+ string methodName, IMessage input)
+ {
+ var proposal = new CreateProposalInput
+ {
+ OrganizationAddress = organizationAddress,
+ ContractMethodName = methodName,
+ ExpiredTime = TimestampHelper.GetUtcNow().AddHours(1),
+ Params = input.ToByteString(),
+ ToAddress = contractAddress
+ };
+
+ var createResult = await ParliamentContractStub.CreateProposal.SendAsync(proposal);
+ var proposalId = createResult.Output;
+
+ return proposalId;
+ }
+
+ private async Task ApproveWithMinersAsync(Hash proposalId)
+ {
+ foreach (var bp in InitialCoreDataCenterKeyPairs)
+ {
+ var tester = GetParliamentContractTester(bp);
+ var approveResult = await tester.Approve.SendAsync(proposalId);
+ }
+ }
+
+ internal async Task CreateSeedNftCollection(TokenContractImplContainer.TokenContractImplStub stub)
+ {
+ var input = new CreateInput
+ {
+ Symbol = SeedNFTSymbolPre + SeedNum,
+ Decimals = 0,
+ IsBurnable = true,
+ TokenName = "seed Collection",
+ TotalSupply = 1,
+ Issuer = DefaultAddress,
+ Owner = DefaultAddress,
+ ExternalInfo = new ExternalInfo()
+ };
+ await stub.Create.SendAsync(input);
+ }
+
+
+ internal async Task CreateSeedNftAsync(TokenContractImplContainer.TokenContractImplStub stub,
+ CreateInput createInput)
+ {
+ var input = BuildSeedCreateInput(createInput);
+ await stub.Create.SendAsync(input);
+ await stub.Issue.SendAsync(new IssueInput
+ {
+ Symbol = input.Symbol,
+ Amount = 1,
+ Memo = "ddd",
+ To = DefaultAddress
+ });
+ return input;
+ }
+
+
+
+ internal async Task> CreateSeedNftWithExceptionAsync(
+ TokenContractImplContainer.TokenContractImplStub stub,
+ CreateInput createInput)
+ {
+ var input = BuildSeedCreateInput(createInput);
+ return await stub.Create.SendWithExceptionAsync(input);
+ }
+
+ internal CreateInput BuildSeedCreateInput(CreateInput createInput)
+ {
+ Interlocked.Increment(ref SeedNum);
+ var input = new CreateInput
+ {
+ Symbol = SeedNFTSymbolPre + SeedNum,
+ Decimals = 0,
+ IsBurnable = true,
+ TokenName = "seed token" + SeedNum,
+ TotalSupply = 1,
+ Issuer = DefaultAddress,
+ Owner = DefaultAddress,
+ ExternalInfo = new ExternalInfo(),
+ LockWhiteList = { TokenContractAddress }
+ };
+ input.ExternalInfo.Value["__seed_owned_symbol"] = createInput.Symbol;
+ input.ExternalInfo.Value["__seed_exp_time"] = TimestampHelper.GetUtcNow().AddDays(1).Seconds.ToString();
+ return input;
+ }
+
+ internal async Task> CreateMutiTokenAsync(
+ TokenContractImplContainer.TokenContractImplStub stub,
+ CreateInput createInput)
+ {
+ await CreateSeedNftAsync(stub, createInput);
+ return await stub.Create.SendAsync(createInput);
+ }
+
+ internal async Task> CreateMutiTokenWithExceptionAsync(
+ TokenContractImplContainer.TokenContractImplStub stub, CreateInput createInput)
+ {
+ await CreateSeedNftAsync(stub, createInput);
+ return await stub.Create.SendWithExceptionAsync(createInput);
+ }
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.MultiToken.Tests/MultiTokenContractWithCustomSystemTransactionTest.cs b/test/AElf.Contracts.MultiToken.Tests/MultiTokenContractWithCustomSystemTransactionTest.cs
index 12a2888fba..f9c91f87b1 100644
--- a/test/AElf.Contracts.MultiToken.Tests/MultiTokenContractWithCustomSystemTransactionTest.cs
+++ b/test/AElf.Contracts.MultiToken.Tests/MultiTokenContractWithCustomSystemTransactionTest.cs
@@ -20,15 +20,6 @@ public MultiTokenContractWithCustomSystemTransactionTest()
private async Task InitializeAsync()
{
- await TokenContractStub.Create.SendAsync(new CreateInput
- {
- Symbol = DefaultSymbol,
- Decimals = 2,
- IsBurnable = true,
- TokenName = "elf token",
- TotalSupply = _totalSupply,
- Issuer = DefaultAddress
- });
await TokenContractStub.SetPrimaryTokenSymbol.SendAsync(new SetPrimaryTokenSymbolInput
{
Symbol = DefaultSymbol
diff --git a/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/MultiTokenContractCrossChainTest.cs b/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/MultiTokenContractCrossChainTest.cs
index c40cc6ed98..4c76a04b09 100644
--- a/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/MultiTokenContractCrossChainTest.cs
+++ b/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/MultiTokenContractCrossChainTest.cs
@@ -195,8 +195,8 @@ public async Task MainChain_CrossChainCreateToken_Test()
// Side chain create token
var createTransaction =
- CreateTransactionForTokenCreation(SideChainTokenContractStub, SideChainTestKit.DefaultAccount.Address,
- SymbolForTesting);
+ await CreateTransactionForTokenCreation(SideChainTokenContractStub, SideChainTestKit.DefaultAccount.Address,
+ SymbolForTesting, SideTokenContractAddress);
var executedSet = await SideChainTestKit.MineAsync(new List { createTransaction });
var createResult = executedSet.TransactionResultMap[createTransaction.GetHash()];
Assert.True(createResult.Status == TransactionResultStatus.Mined, createResult.Error);
@@ -236,8 +236,8 @@ public async Task SideChain_CrossChainCreateToken_Test()
// Main chain create token
await BootMinerChangeRoundAsync(AEDPoSContractStub, true);
- var createTransaction = CreateTransactionForTokenCreation(TokenContractStub,
- DefaultAccount.Address, SymbolForTesting);
+ var createTransaction = await CreateTransactionForTokenCreation(TokenContractStub,
+ DefaultAccount.Address, SymbolForTesting, TokenContractAddress);
var blockExecutedSet = await MineAsync(new List { createTransaction });
var createResult = blockExecutedSet.TransactionResultMap[createTransaction.GetHash()];
Assert.True(createResult.Status == TransactionResultStatus.Mined, createResult.Error);
@@ -328,14 +328,13 @@ public async Task SideChain_CrossChainCreateToken_WithAlreadyCreated_Test()
await RegisterSideChainContractAddressOnMainChainAsync();
await BootMinerChangeRoundAsync(AEDPoSContractStub, true);
- var createTransaction = CreateTransactionForTokenCreation(TokenContractStub,
- DefaultAccount.Address, SymbolForTesting);
+ var createTransaction = await CreateTransactionForTokenCreation(TokenContractStub,
+ DefaultAccount.Address, SymbolForTesting, TokenContractAddress);
var blockExecutedSet = await MineAsync(new List { createTransaction });
var createResult = blockExecutedSet.TransactionResultMap[createTransaction.GetHash()];
Assert.True(createResult.Status == TransactionResultStatus.Mined, createResult.Error);
-
- var sideCreateTransaction = CreateTransactionForTokenCreation(SideChainTokenContractStub,
- SideChainTestKit.DefaultAccount.Address, SymbolForTesting);
+ var sideCreateTransaction = await CreateTransactionForTokenCreation(SideChainTokenContractStub,
+ SideChainTestKit.DefaultAccount.Address, SymbolForTesting, SideTokenContractAddress);
blockExecutedSet = await SideChainTestKit.MineAsync(new List { sideCreateTransaction });
var sideCreateResult = blockExecutedSet.TransactionResultMap[sideCreateTransaction.GetHash()];
Assert.True(sideCreateResult.Status == TransactionResultStatus.Mined, sideCreateResult.Error);
@@ -437,8 +436,8 @@ public async Task MainChain_CrossChainTransfer_NativeToken_Test()
[Fact]
public async Task MainChain_CrossChainTransfer_Without_Burnable_Token_Test()
{
- var createTransaction = CreateTransactionForTokenCreation(TokenContractStub,
- DefaultAccount.Address, SymbolForTesting, false);
+ var createTransaction = await CreateTransactionForTokenCreation(TokenContractStub,
+ DefaultAccount.Address, SymbolForTesting, TokenContractAddress, false);
var blockExecutedSet = await MineAsync(new List { createTransaction });
var createResult = blockExecutedSet.TransactionResultMap[createTransaction.GetHash()];
Assert.True(createResult.Status == TransactionResultStatus.Mined, createResult.Error);
@@ -471,8 +470,8 @@ public async Task MainChain_CrossChainTransfer_Test()
// Main chain create token
await BootMinerChangeRoundAsync(AEDPoSContractStub, true);
- var createTransaction = CreateTransactionForTokenCreation(TokenContractStub,
- DefaultAccount.Address, SymbolForTesting);
+ var createTransaction = await CreateTransactionForTokenCreation(TokenContractStub,
+ DefaultAccount.Address, SymbolForTesting, TokenContractAddress);
var executedSet = await MineAsync(new List { createTransaction });
var createResult = executedSet.TransactionResultMap[createTransaction.GetHash()];
Assert.True(createResult.Status == TransactionResultStatus.Mined, createResult.Error);
@@ -488,6 +487,7 @@ public async Task MainChain_CrossChainTransfer_Test()
Symbol = createdTokenInfo.Symbol,
Decimals = createdTokenInfo.Decimals,
Issuer = createdTokenInfo.Issuer,
+ Owner = createdTokenInfo.Issuer,
IsBurnable = createdTokenInfo.IsBurnable,
TotalSupply = createdTokenInfo.TotalSupply,
IssueChainId = createdTokenInfo.IssueChainId
@@ -648,10 +648,11 @@ public async Task SideChain_CrossChainReceived_NativeToken_Test()
TransferTransactionBytes = crossChainTransferTransaction.ToByteString(),
MerklePath = transferMerKlePath
};
- var receiveResult = await SideChainTokenContractStub.CrossChainReceiveToken.SendAsync(crossChainReceiveTokenInput);
-
+ var receiveResult =
+ await SideChainTokenContractStub.CrossChainReceiveToken.SendAsync(crossChainReceiveTokenInput);
+
var logEvent = receiveResult.TransactionResult.Logs.First(l => l.Name == nameof(CrossChainReceived));
- var receivedEvent =new CrossChainReceived();
+ var receivedEvent = new CrossChainReceived();
receivedEvent.MergeFrom(logEvent.NonIndexed);
receivedEvent.From.ShouldBe(SideChainTestKit.DefaultAccount.Address);
receivedEvent.To.ShouldBe(SideChainTestKit.DefaultAccount.Address);
@@ -723,8 +724,8 @@ public async Task SideChain_CrossChainReceived_InvalidToken_Test()
await RegisterMainChainTokenContractAddressOnSideChainAsync(sideChainId);
var transferAmount = 1000;
- var createTransaction = CreateTransactionForTokenCreation(TokenContractStub,
- DefaultAccount.Address, SymbolForTesting);
+ var createTransaction = await CreateTransactionForTokenCreation(TokenContractStub,
+ DefaultAccount.Address, SymbolForTesting, TokenContractAddress);
var executedSet = await MineAsync(new List { createTransaction });
var createResult = executedSet.TransactionResultMap[createTransaction.GetHash()];
createResult.Status.ShouldBe(TransactionResultStatus.Mined, createResult.Error);
@@ -809,8 +810,8 @@ public async Task SideChain_CrossChainReceived_DifferentReceiver_Test()
public async Task CrossChainCreateToken_WithoutRegister_Test()
{
await GenerateSideChainAsync(false);
- var createTransaction = CreateTransactionForTokenCreation(TokenContractStub,
- DefaultAccount.Address, SymbolForTesting);
+ var createTransaction = await CreateTransactionForTokenCreation(TokenContractStub,
+ DefaultAccount.Address, SymbolForTesting, TokenContractAddress);
var blockExecutedSet = await MineAsync(new List { createTransaction });
var createResult = blockExecutedSet.TransactionResultMap[createTransaction.GetHash()];
Assert.True(createResult.Status == TransactionResultStatus.Mined, createResult.Error);
@@ -871,22 +872,27 @@ private Transaction ValidateTransaction(Address tokenContractAddress, Hash name,
}
- private Transaction CreateTransactionForTokenCreation(
+ private async Task CreateTransactionForTokenCreation(
TokenContractImplContainer.TokenContractImplStub tokenContractImplStub,
- Address issuer, string symbol, bool isBurnable = true)
+ Address issuer, string symbol, Address lockWhiteAddress, bool isBurnable = true)
{
+ await CreateSeedNftCollection(tokenContractImplStub, issuer);
var tokenInfo = GetTokenInfo(symbol, issuer, isBurnable);
- return tokenContractImplStub.Create.GetTransaction(new CreateInput
+ var input = new CreateInput
{
Symbol = tokenInfo.Symbol,
Decimals = tokenInfo.Decimals,
Issuer = tokenInfo.Issuer,
+ Owner = tokenInfo.Issuer,
IsBurnable = tokenInfo.IsBurnable,
TokenName = tokenInfo.TokenName,
TotalSupply = tokenInfo.TotalSupply
- });
+ };
+ await CreateSeedNftAsync(tokenContractImplStub, input, lockWhiteAddress);
+ return tokenContractImplStub.Create.GetTransaction(input);
}
+
private Transaction CreateTokenInfoValidationTransaction(TokenInfo createdTokenInfo,
TokenContractImplContainer.TokenContractImplStub tokenContractImplStub)
{
@@ -896,6 +902,7 @@ private Transaction CreateTokenInfoValidationTransaction(TokenInfo createdTokenI
Symbol = createdTokenInfo.Symbol,
Decimals = createdTokenInfo.Decimals,
Issuer = createdTokenInfo.Issuer,
+ Owner = createdTokenInfo.Issuer,
IsBurnable = createdTokenInfo.IsBurnable,
TotalSupply = createdTokenInfo.TotalSupply,
IssueChainId = createdTokenInfo.IssueChainId
diff --git a/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/MultiTokenContractCrossChainTestBase.cs b/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/MultiTokenContractCrossChainTestBase.cs
index ca4e882201..a84a9d9d98 100644
--- a/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/MultiTokenContractCrossChainTestBase.cs
+++ b/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/MultiTokenContractCrossChainTestBase.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using AElf.Contracts.Consensus.AEDPoS;
using AElf.Contracts.CrossChain;
@@ -8,9 +9,12 @@
using AElf.Contracts.Referendum;
using AElf.ContractTestBase.ContractTestKit;
using AElf.CrossChain;
+using AElf.Cryptography;
+using AElf.Cryptography.ECDSA;
using AElf.CSharp.Core;
using AElf.CSharp.Core.Extension;
using AElf.Kernel;
+using AElf.Kernel.Blockchain.Application;
using AElf.Kernel.Consensus;
using AElf.Kernel.Proposal;
using AElf.Kernel.SmartContract;
@@ -61,6 +65,8 @@ public class MultiTokenContractCrossChainTestBase : ContractTestBase SideChainTestKit;
internal TokenContractImplContainer.TokenContractImplStub SideChainTokenContractStub;
+ protected readonly IBlockchainService BlockchainService;
+
protected Address SideConsensusAddress;
@@ -73,6 +79,9 @@ public class MultiTokenContractCrossChainTestBase : ContractTestBase>()
.Value.ContextVariables["SymbolListToPayRental"].Split(",").ToList();
+
+ BlockchainService = Application.ServiceProvider.GetRequiredService();
}
protected Timestamp BlockchainStartTimestamp => TimestampHelper.GetUtcNow();
@@ -318,10 +329,11 @@ internal async Task BootMinerChangeRoundAsync(AEDPoSContractContainer.AEDPoSCont
{
if (isMainChain)
{
+ var randomNumber = await GenerateRandomProofAsync(aedPoSContractStub, DefaultAccount.KeyPair);
var currentRound = await aedPoSContractStub.GetCurrentRoundInformation.CallAsync(new Empty());
var expectedStartTime = TimestampHelper.GetUtcNow();
currentRound.GenerateNextRoundInformation(expectedStartTime, BlockchainStartTimestamp,
- out var nextRound);
+ ByteString.CopyFrom(randomNumber), out var nextRound);
nextRound.RealTimeMinersInformation[DefaultAccount.KeyPair.PublicKey.ToHex()]
.ExpectedMiningTime = expectedStartTime;
await aedPoSContractStub.NextRound.SendAsync(nextRound);
@@ -329,13 +341,14 @@ internal async Task BootMinerChangeRoundAsync(AEDPoSContractContainer.AEDPoSCont
if (!isMainChain)
{
+ var randomNumber = CryptoHelper.ECVrfProve(DefaultAccount.KeyPair, Hash.Empty.ToByteArray());
var currentRound = await aedPoSContractStub.GetCurrentRoundInformation.CallAsync(new Empty());
var expectedStartTime = BlockchainStartTimestamp.ToDateTime()
.AddMilliseconds(
((long)currentRound.TotalMilliseconds(4000)).Mul(
nextRoundNumber.Sub(1)));
currentRound.GenerateNextRoundInformation(expectedStartTime.ToTimestamp(), BlockchainStartTimestamp,
- out var nextRound);
+ ByteString.CopyFrom(randomNumber), out var nextRound);
if (currentRound.RoundNumber >= 3)
{
@@ -353,6 +366,18 @@ internal async Task BootMinerChangeRoundAsync(AEDPoSContractContainer.AEDPoSCont
}
}
+ private async Task GenerateRandomProofAsync(AEDPoSContractContainer.AEDPoSContractStub aedPoSContractStub,
+ ECKeyPair keyPair)
+ {
+ var blockHeight = (await BlockchainService.GetChainAsync()).BestChainHeight;
+ var previousRandomHash =
+ blockHeight <= 1
+ ? Hash.Empty
+ : await aedPoSContractStub.GetRandomHash.CallAsync(new Int64Value
+ { Value = blockHeight });
+ return CryptoHelper.ECVrfProve(keyPair, previousRandomHash.ToByteArray());
+ }
+
private async Task ApproveBalanceAsync(long amount)
{
await TokenContractStub.Approve.SendAsync(new ApproveInput
@@ -372,4 +397,57 @@ await CrossChainContractStub.Initialize.SendAsync(new InitializeInput
CreationHeightOnParentChain = parentChainHeightOfCreation
});
}
+
+ internal async Task CreateSeedNftCollection(TokenContractImplContainer.TokenContractImplStub stub, Address address)
+ {
+ var input = new CreateInput
+ {
+ Symbol = SeedNFTSymbolPre + 0,
+ Decimals = 0,
+ IsBurnable = true,
+ TokenName = "seed Collection",
+ TotalSupply = 1,
+ Issuer = address,
+ Owner = address,
+ ExternalInfo = new ExternalInfo()
+ };
+ var re= await stub.Create.SendAsync(input);
+ }
+
+
+ internal async Task CreateSeedNftAsync(TokenContractImplContainer.TokenContractImplStub stub,
+ CreateInput createInput,Address lockWhiteAddress)
+ {
+ var input = BuildSeedCreateInput(createInput,lockWhiteAddress);
+ await stub.Create.SendAsync(input);
+ await stub.Issue.SendAsync(new IssueInput
+ {
+ Symbol = input.Symbol,
+ Amount = 1,
+ Memo = "ddd",
+ To = input.Issuer
+ });
+ return input;
+ }
+
+ internal CreateInput BuildSeedCreateInput(CreateInput createInput,Address lockWhiteAddress)
+ {
+ Interlocked.Increment(ref SeedNum);
+ var input = new CreateInput
+ {
+ Symbol = SeedNFTSymbolPre + SeedNum,
+ Decimals = 0,
+ IsBurnable = true,
+ TokenName = "seed token" + SeedNum,
+ TotalSupply = 1,
+ Issuer = createInput.Issuer,
+ Owner = createInput.Issuer,
+ ExternalInfo = new ExternalInfo(),
+ LockWhiteList = { lockWhiteAddress }
+ };
+ input.ExternalInfo.Value["__seed_owned_symbol"] = createInput.Symbol;
+ input.ExternalInfo.Value["__seed_exp_time"] = TimestampHelper.GetUtcNow().AddDays(1).Seconds.ToString();
+ return input;
+ }
+
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/MultiTokenContractReferenceFeeTest.cs b/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/MultiTokenContractReferenceFeeTest.cs
index 4db7135097..f32c400c35 100644
--- a/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/MultiTokenContractReferenceFeeTest.cs
+++ b/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/MultiTokenContractReferenceFeeTest.cs
@@ -496,14 +496,18 @@ public async Task SetSymbolsToPayTxSizeFee_With_Invalid_Weight_Test()
var theDefaultController = await GetDefaultParliamentAddressAsync();
var primaryTokenSymbol = await GetThePrimaryTokenAsync();
var feeToken = "FEETOKEN";
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateSeedNftCollection(TokenContractStub, DefaultAccount.Address);
+ var input = new CreateInput
{
Symbol = feeToken,
TokenName = "name",
- Issuer = TokenContractAddress,
+ Issuer = DefaultAccount.Address,
TotalSupply = 100_000,
- IsBurnable = true
- });
+ IsBurnable = true,
+ Owner = DefaultAccount.Address
+ };
+ await CreateSeedNftAsync(TokenContractStub, input, TokenContractAddress);
+ await TokenContractStub.Create.SendAsync(input);
var newSymbolList = new SymbolListToPayTxSizeFee();
newSymbolList.SymbolsToPayTxSizeFee.Add(new SymbolToPayTxSizeFee
{
@@ -531,13 +535,17 @@ public async Task SetSymbolsToPayTxSizeFee_With_Repeat_Token_Test()
var theDefaultController = await GetDefaultParliamentAddressAsync();
var primaryTokenSymbol = await GetThePrimaryTokenAsync();
var feeToken = "FEETOKEN";
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateSeedNftCollection(TokenContractStub, DefaultAccount.Address);
+ var input = new CreateInput
{
Symbol = feeToken,
TokenName = "name",
- Issuer = TokenContractAddress,
- TotalSupply = 100_000
- });
+ Issuer = DefaultAccount.Address,
+ TotalSupply = 100_000,
+ Owner = DefaultAccount.Address
+ };
+ await CreateSeedNftAsync(TokenContractStub, input, TokenContractAddress);
+ await TokenContractStub.Create.SendAsync(input);
var newSymbolList = new SymbolListToPayTxSizeFee
{
SymbolsToPayTxSizeFee =
@@ -572,13 +580,17 @@ public async Task SetSymbolsToPayTxSizeFee_Without_PrimaryToken_Test()
{
var theDefaultController = await GetDefaultParliamentAddressAsync();
var feeToken = "FEETOKEN";
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateSeedNftCollection(TokenContractStub, DefaultAccount.Address);
+ var input = new CreateInput
{
Symbol = feeToken,
TokenName = "name",
- Issuer = TokenContractAddress,
- TotalSupply = 100_000
- });
+ Issuer = DefaultAccount.Address,
+ TotalSupply = 100_000,
+ Owner = DefaultAccount.Address
+ };
+ await CreateSeedNftAsync(TokenContractStub, input, TokenContractAddress);
+ await TokenContractStub.Create.SendAsync(input);
var newSymbolList = new SymbolListToPayTxSizeFee();
newSymbolList.SymbolsToPayTxSizeFee.Add(new SymbolToPayTxSizeFee
{
@@ -596,13 +608,17 @@ public async Task SetSymbolsToPayTxSizeFee_Without_Profitable_Token_Test()
var theDefaultController = await GetDefaultParliamentAddressAsync();
var primaryTokenSymbol = await GetThePrimaryTokenAsync();
const string feeToken = "FEETOKEN";
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateSeedNftCollection(TokenContractStub, DefaultAccount.Address);
+ var input = new CreateInput
{
Symbol = feeToken,
TokenName = "name",
- Issuer = TokenContractAddress,
- TotalSupply = 100_000
- });
+ Issuer = DefaultAccount.Address,
+ TotalSupply = 100_000,
+ Owner = DefaultAccount.Address
+ };
+ await CreateSeedNftAsync(TokenContractStub, input, TokenContractAddress);
+ await TokenContractStub.Create.SendAsync(input);
var newSymbolList = new SymbolListToPayTxSizeFee
{
SymbolsToPayTxSizeFee =
@@ -648,7 +664,8 @@ await TokenContractStub.Create.SendAsync(new CreateInput
TokenName = "name",
Issuer = TokenContractAddress,
TotalSupply = newTokenTotalSupply,
- IsBurnable = true
+ IsBurnable = true,
+ Owner = TokenContractAddress
});
var invalidBaseTokenWeight = (int)long.MaxValue.Div(newTokenTotalSupply).Add(1);
newSymbolList.SymbolsToPayTxSizeFee.Add(new SymbolToPayTxSizeFee
@@ -695,14 +712,18 @@ public async Task SetSymbolsToPayTxSizeFee_Success_Test()
var theDefaultController = await GetDefaultParliamentAddressAsync();
var primaryTokenSymbol = await GetThePrimaryTokenAsync();
const string feeToken = "FEETOKEN";
- await TokenContractStub.Create.SendAsync(new CreateInput
+ await CreateSeedNftCollection(TokenContractStub, DefaultAccount.Address);
+ var input = new CreateInput
{
Symbol = feeToken,
TokenName = "name",
- Issuer = TokenContractAddress,
+ Issuer = DefaultAccount.Address,
TotalSupply = 100_000,
- IsBurnable = true
- });
+ IsBurnable = true,
+ Owner = DefaultAccount.Address
+ };
+ await CreateSeedNftAsync(TokenContractStub, input, TokenContractAddress);
+ await TokenContractStub.Create.SendAsync(input);
var newSymbolList = new SymbolListToPayTxSizeFee
{
SymbolsToPayTxSizeFee =
diff --git a/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/SideChainUnitTestTokenContractInitializationProvider.cs b/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/SideChainUnitTestTokenContractInitializationProvider.cs
index e6f9791681..aeb8d3148a 100644
--- a/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/SideChainUnitTestTokenContractInitializationProvider.cs
+++ b/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/SideChainUnitTestTokenContractInitializationProvider.cs
@@ -127,6 +127,7 @@ private CreateInput GenerateTokenCreateInput(TokenInfo tokenInfo)
Decimals = tokenInfo.Decimals,
IssueChainId = tokenInfo.IssueChainId,
Issuer = tokenInfo.Issuer,
+ Owner = tokenInfo.Issuer,
IsBurnable = tokenInfo.IsBurnable,
Symbol = tokenInfo.Symbol,
TokenName = tokenInfo.TokenName,
diff --git a/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/Types/Round_Generation.cs b/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/Types/Round_Generation.cs
index 34830558d0..63ca824cd6 100644
--- a/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/Types/Round_Generation.cs
+++ b/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/Types/Round_Generation.cs
@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using AElf.CSharp.Core;
+using AElf.Types;
+using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
namespace AElf.Contracts.Consensus.AEDPoS;
@@ -8,9 +10,9 @@ namespace AElf.Contracts.Consensus.AEDPoS;
internal partial class Round
{
public bool GenerateNextRoundInformation(Timestamp currentBlockTimestamp, Timestamp blockchainStartTimestamp,
- out Round nextRound)
+ ByteString randomNumber, out NextRoundInput nextRound)
{
- nextRound = new Round();
+ nextRound = new NextRoundInput();
var minersMinedCurrentRound = GetMinedMiners();
var minersNotMinedCurrentRound = GetNotMinedMiners();
@@ -65,7 +67,8 @@ public bool GenerateNextRoundInformation(Timestamp currentBlockTimestamp, Timest
nextRound.RealTimeMinersInformation.Values.First().IsExtraBlockProducer = true;
else
expectedExtraBlockProducer.IsExtraBlockProducer = true;
-
+ nextRound.RandomNumber = randomNumber;
+
return true;
}
diff --git a/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/UnitTestTokenContractInitializationProvider.cs b/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/UnitTestTokenContractInitializationProvider.cs
index b9df291357..cc84673ccf 100644
--- a/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/UnitTestTokenContractInitializationProvider.cs
+++ b/test/AElf.Contracts.MultiTokenCrossChainTransfer.Tests/UnitTestTokenContractInitializationProvider.cs
@@ -38,6 +38,7 @@ public override List GetInitializeMethodList(b
{
Decimals = _economicOptions.Decimals,
Issuer = address,
+ Owner = address,
IsBurnable = _economicOptions.IsBurnable,
Symbol = _economicOptions.Symbol,
TokenName = _economicOptions.TokenName,
diff --git a/test/AElf.Contracts.Parliament.Tests/ParliamentContractTest.cs b/test/AElf.Contracts.Parliament.Tests/ParliamentContractTest.cs
index 143c27a168..5a82089232 100644
--- a/test/AElf.Contracts.Parliament.Tests/ParliamentContractTest.cs
+++ b/test/AElf.Contracts.Parliament.Tests/ParliamentContractTest.cs
@@ -32,32 +32,9 @@ public ParliamentContractTest()
InitializeContracts();
}
- [Fact]
- public async Task Get_DefaultOrganizationAddress_Test()
- {
- var transactionResult =
- await ParliamentContractStub.GetDefaultOrganizationAddress.SendWithExceptionAsync(new Empty());
- transactionResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
- transactionResult.TransactionResult.Error.Contains("Not initialized.").ShouldBeTrue();
-
- await InitializeParliamentContracts();
- var defaultParliamentAddress =
- await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
- defaultParliamentAddress.ShouldNotBeNull();
- }
-
- [Fact]
- public async Task ParliamentContract_Initialize_Test()
- {
- var result = await ParliamentContractStub.Initialize.SendAsync(new InitializeInput());
- result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
- }
-
[Fact]
public async Task ParliamentContract_InitializeTwice_Test()
{
- await ParliamentContract_Initialize_Test();
-
var result = await ParliamentContractStub.Initialize.SendWithExceptionAsync(new InitializeInput());
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
result.TransactionResult.Error.Contains("Already initialized.").ShouldBeTrue();
@@ -66,7 +43,7 @@ public async Task ParliamentContract_InitializeTwice_Test()
[Fact]
public async Task Get_Organization_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 10000 / MinersCount;
var maximalAbstentionThreshold = 2000 / MinersCount;
var maximalRejectionThreshold = 3000 / MinersCount;
@@ -110,7 +87,7 @@ public async Task Get_OrganizationFailed_Test()
[Fact]
public async Task Get_Proposal_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -152,7 +129,7 @@ public async Task ApproveMultiProposals_Without_Authority_Test()
[Fact]
public async Task ApproveMultiProposals_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -185,7 +162,7 @@ public async Task Get_ProposalFailed_Test()
[Fact]
public async Task Create_OrganizationFailed_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -204,13 +181,7 @@ public async Task Create_OrganizationFailed_Test()
};
var minerParliamentContractStub = GetParliamentContractTester(InitialMinersKeyPairs[0]);
-
- {
- var transactionResult =
- await ParliamentContractStub.CreateOrganization.SendWithExceptionAsync(createOrganizationInput);
- transactionResult.TransactionResult.Error.ShouldContain("Unauthorized to create organization.");
- }
-
+
{
createOrganizationInput.ProposalReleaseThreshold = proposalReleaseThreshold;
createOrganizationInput.ProposalReleaseThreshold.MinimalApprovalThreshold = 10000;
@@ -280,7 +251,7 @@ public async Task Create_OrganizationFailed_Test()
[Fact]
public async Task Create_ProposalFailed_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -325,7 +296,7 @@ public async Task Create_ProposalFailed_Test()
}
//"Expired proposal."
{
- createProposalInput.ExpiredTime = TimestampHelper.GetUtcNow().AddSeconds(-1);
+ createProposalInput.ExpiredTime = TimestampHelper.GetUtcNow().AddMinutes(-10);
var transactionResult =
await ParliamentContractStub.CreateProposal.SendWithExceptionAsync(createProposalInput);
transactionResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
@@ -374,7 +345,7 @@ public async Task Approve_Proposal_NotFoundProposal_Test()
[Fact]
public async Task Approve_Proposal_NotAuthorizedApproval_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -392,7 +363,7 @@ public async Task Approve_Proposal_NotAuthorizedApproval_Test()
[Fact]
public async Task Approve_Proposal_ExpiredTime_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -410,7 +381,7 @@ public async Task Approve_Proposal_ExpiredTime_Test()
[Fact]
public async Task Approve_Proposal_ApprovalAlreadyExists_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -436,7 +407,7 @@ public async Task Approve_Proposal_ApprovalAlreadyExists_Test()
[Fact]
public async Task Reject_Without_Authority_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -453,7 +424,7 @@ public async Task Reject_Without_Authority_Test()
[Fact]
public async Task Reject_With_Invalid_Proposal_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -482,7 +453,7 @@ public async Task Reject_With_Invalid_Proposal_Test()
[Fact]
public async Task Reject_Approved_Proposal_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -501,7 +472,7 @@ public async Task Reject_Approved_Proposal_Test()
[Fact]
public async Task Reject_Success_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -519,7 +490,7 @@ public async Task Reject_Success_Test()
[Fact]
public async Task Abstain_Without_Authority_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -536,7 +507,7 @@ public async Task Abstain_Without_Authority_Test()
[Fact]
public async Task Abstain_With_Invalid_Proposal_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -565,7 +536,7 @@ public async Task Abstain_With_Invalid_Proposal_Test()
[Fact]
public async Task Abstain_Approved_Proposal_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -584,7 +555,7 @@ public async Task Abstain_Approved_Proposal_Test()
[Fact]
public async Task Abstain_Success_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -602,7 +573,7 @@ public async Task Abstain_Success_Test()
[Fact]
public async Task Check_Proposal_ToBeReleased()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
{
var minimalApprovalThreshold = 3000;
@@ -676,7 +647,7 @@ public async Task Check_Proposal_ToBeReleased()
[Fact]
public async Task Release_NotEnoughApprove_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -706,7 +677,7 @@ public async Task Release_NotFound_Test()
[Fact]
public async Task Release_WrongSender_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -727,7 +698,7 @@ public async Task Release_WrongSender_Test()
[Fact]
public async Task Release_Expired_Proposal_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -744,7 +715,7 @@ public async Task Release_Expired_Proposal_Test()
[Fact]
public async Task Release_Proposal_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -776,7 +747,7 @@ public async Task Release_Proposal_Test()
[Fact]
public async Task Release_Proposal_AlreadyReleased_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -818,7 +789,7 @@ await ParliamentContractStub.ChangeOrganizationThreshold.SendWithExceptionAsync(
[Fact]
public async Task Change_OrganizationThreshold_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 3000;
var maximalAbstentionThreshold = 3000;
var maximalRejectionThreshold = 3000;
@@ -881,7 +852,7 @@ public async Task Change_OrganizationThreshold_Test()
[Fact]
public async Task Check_ValidProposal_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6000;
var maximalAbstentionThreshold = 2000;
@@ -929,7 +900,7 @@ public async Task Check_ValidProposal_Test()
[Fact]
public async Task Clear_NotExpiredProposal_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var defaultParliamentAddress =
await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
var miner = InitialMinersKeyPairs[1];
@@ -950,7 +921,7 @@ public async Task Clear_NotExpiredProposal_Test()
[Fact]
public async Task Clear_ExpiredProposal_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
@@ -974,7 +945,7 @@ public async Task Clear_ExpiredProposal_Test()
[Fact]
public async Task ChangeMethodFeeController_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var parliamentContractStub = GetParliamentContractTester(InitialMinersKeyPairs[0]);
var createOrganizationResult =
await parliamentContractStub.CreateOrganization.SendAsync(
@@ -1014,7 +985,7 @@ await parliamentContractStub.CreateOrganization.SendAsync(
[Fact]
public async Task ChangeMethodFeeController_WithoutAuth_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -1037,7 +1008,7 @@ public async Task ChangeMethodFeeController_WithoutAuth_Test()
[Fact]
public async Task ChangeMethodFeeController_With_Invalid_Authority_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var parliamentContractStub = GetParliamentContractTester(InitialMinersKeyPairs[0]);
@@ -1103,7 +1074,7 @@ public async Task SetMethodFee_With_Invalid_Input_Test()
[Fact]
public async Task SetMethodFee_Without_Authority_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var setMethodFeeRet = await ParliamentContractStub.SetMethodFee.SendWithExceptionAsync(new MethodFees
{
MethodName = nameof(ParliamentContractStub.Abstain),
@@ -1122,7 +1093,7 @@ public async Task SetMethodFee_Without_Authority_Test()
[Fact]
public async Task SetMethodFee_Success_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var parliamentContractStub = GetParliamentContractTester(InitialMinersKeyPairs[0]);
var methodFeeController = await parliamentContractStub.GetMethodFeeController.CallAsync(new Empty());
var methodFeeName = nameof(parliamentContractStub.Abstain);
@@ -1213,7 +1184,7 @@ await _smartContractAddressService.SetSmartContractAddressAsync(blockIndex,
[Fact]
public async Task ValidateOrganizationExist_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -1233,10 +1204,10 @@ public async Task ValidateOrganizationExist_Test()
public async Task ValidateProposerInWhiteList_Test()
{
var proposer = DefaultSender;
- await ParliamentContractStub.Initialize.SendAsync(new InitializeInput
- {
- PrivilegedProposer = proposer
- });
+ // await ParliamentContractStub.Initialize.SendAsync(new InitializeInput
+ // {
+ // PrivilegedProposer = proposer
+ // });
var isProposerInWhitelist =
await ParliamentContractStub.ValidateProposerInWhiteList.CallAsync(new ValidateProposerInWhiteListInput
{
@@ -1287,10 +1258,10 @@ await _smartContractAddressService.SetSmartContractAddressAsync(blockIndex,
[Fact]
public async Task CreateProposalBySystemContract_Success_Test()
{
- await ParliamentContractStub.Initialize.SendAsync(new InitializeInput
- {
- PrivilegedProposer = DefaultSender
- });
+ // await ParliamentContractStub.Initialize.SendAsync(new InitializeInput
+ // {
+ // PrivilegedProposer = DefaultSender
+ // });
var defaultParliamentAddress =
await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
var chain = _blockchainService.GetChainAsync();
@@ -1338,7 +1309,7 @@ public async Task GetNotVotedProposals_With_Invalid_Proposal_Test()
//fail to validate proposal, proposal expires
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -1372,7 +1343,7 @@ public async Task GetNotVotedPendingProposals_With_Invalid_Proposal_Test()
}
//fail to validate proposal, proposal expires
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -1395,7 +1366,7 @@ public async Task GetNotVotedPendingProposals_With_Invalid_Proposal_Test()
[Fact]
public async Task ApproveMultiProposals_With_Invalid_Proposal_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6667;
var maximalAbstentionThreshold = 2000;
var maximalRejectionThreshold = 3000;
@@ -1417,7 +1388,7 @@ await ParliamentContractStub.ApproveMultiProposals.SendAsync(new ProposalIdList
[Fact]
public async Task Check_ValidProposal_With_Rejected_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 6000;
var maximalAbstentionThreshold = 1;
@@ -1461,7 +1432,7 @@ public async Task Check_ValidProposal_With_Rejected_Test()
[Fact]
public async Task GetReleaseThresholdReachedProposals_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 3000;
var maximalAbstentionThreshold = 3000;
@@ -1504,7 +1475,7 @@ public async Task GetReleaseThresholdReachedProposals_Test()
[Fact]
public async Task GetAvailableProposals_Test()
{
- await InitializeParliamentContracts();
+ // await InitializeParliamentContracts();
var minimalApprovalThreshold = 3000;
var maximalAbstentionThreshold = 3000;
diff --git a/test/AElf.Contracts.Parliament.Tests/ParliamentContractTestBase.cs b/test/AElf.Contracts.Parliament.Tests/ParliamentContractTestBase.cs
index 4cc77daaa3..d70eac58c3 100644
--- a/test/AElf.Contracts.Parliament.Tests/ParliamentContractTestBase.cs
+++ b/test/AElf.Contracts.Parliament.Tests/ParliamentContractTestBase.cs
@@ -8,6 +8,7 @@
using AElf.Contracts.TestBase;
using AElf.ContractTestKit;
using AElf.Cryptography.ECDSA;
+using AElf.CSharp.Core.Extension;
using AElf.Kernel;
using AElf.Kernel.Consensus;
using AElf.Kernel.Proposal;
@@ -37,6 +38,9 @@ public class ParliamentContractTestBase : ContractTestKit.ContractTestBase Accounts[10].Address;
protected Address Tester => Accounts[MinersCount + 1].Address;
+ protected List InitialCoreDataCenterKeyPairs =>
+ Accounts.Take(3).Select(a => a.KeyPair).ToList();
+
protected Address TokenContractAddress { get; set; }
protected Address ConsensusContractAddress { get; set; }
protected Address ParliamentContractAddress { get; set; }
@@ -66,6 +70,20 @@ protected void InitializeContracts()
DefaultSenderKeyPair
));
ParliamentContractStub = GetParliamentContractTester(DefaultSenderKeyPair);
+ AsyncHelper.RunSync(() => ParliamentContractStub.Initialize.SendAsync(new InitializeInput
+ {
+ ProposerAuthorityRequired = false,
+ PrivilegedProposer = DefaultSender
+ }));
+
+ ConsensusContractAddress = AsyncHelper.RunSync(() => DeploySystemSmartContract(
+ KernelConstants.CodeCoverageRunnerCategory,
+ DPoSConsensusCode,
+ ConsensusSmartContractAddressNameProvider.Name,
+ DefaultSenderKeyPair));
+ ConsensusContractStub = GetConsensusContractTester(DefaultSenderKeyPair);
+ AsyncHelper.RunSync(async () => await InitializeConsensusAsync());
+
//deploy token contract
TokenContractAddress = AsyncHelper.RunSync(() =>
DeploySystemSmartContract(
@@ -75,14 +93,6 @@ protected void InitializeContracts()
DefaultSenderKeyPair));
TokenContractStub = GetTokenContractTester(DefaultSenderKeyPair);
AsyncHelper.RunSync(async () => await InitializeTokenAsync());
-
- ConsensusContractAddress = AsyncHelper.RunSync(() => DeploySystemSmartContract(
- KernelConstants.CodeCoverageRunnerCategory,
- DPoSConsensusCode,
- ConsensusSmartContractAddressNameProvider.Name,
- DefaultSenderKeyPair));
- ConsensusContractStub = GetConsensusContractTester(DefaultSenderKeyPair);
- AsyncHelper.RunSync(async () => await InitializeConsensusAsync());
}
@@ -112,15 +122,23 @@ private async Task InitializeTokenAsync()
{
const string symbol = "ELF";
const long totalSupply = 100_000_000;
- await TokenContractStub.Create.SendAsync(new CreateInput
+
+ var organizationAddress =
+ (await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty()));
+ var approveProposalId = await CreateParliamentProposalAsync(nameof(TokenContractStub.Create), organizationAddress, new CreateInput
{
Symbol = symbol,
Decimals = 2,
IsBurnable = true,
TokenName = "elf token",
TotalSupply = totalSupply,
- Issuer = DefaultSender
- });
+ Issuer = DefaultSender,
+ Owner = DefaultSender
+ }, TokenContractAddress);
+ await ApproveWithMinersAsync(approveProposalId);
+ await ParliamentContractStub.Release.SendAsync(approveProposalId);
+
+
await TokenContractStub.Issue.SendAsync(new IssueInput
{
Symbol = symbol,
@@ -144,7 +162,34 @@ await ConsensusContractStub.FirstRound.SendAsync(
internal async Task InitializeParliamentContracts()
{
- await ParliamentContractStub.Initialize.SendAsync(new InitializeInput());
+ await ParliamentContractStub.Initialize.SendAsync(new InitializeInput
+ {
+ ProposerAuthorityRequired = false,
+ PrivilegedProposer = DefaultSender
+ });
+ }
+
+ internal async Task CreateParliamentProposalAsync(string method, Address organizationAddress,
+ IMessage input, Address toAddress = null)
+ {
+ var proposal = (await ParliamentContractStub.CreateProposal.SendAsync(new CreateProposalInput
+ {
+ ToAddress = toAddress,
+ ContractMethodName = method,
+ ExpiredTime = TimestampHelper.GetUtcNow().AddDays(1),
+ OrganizationAddress = organizationAddress,
+ Params = input.ToByteString()
+ })).Output;
+ return proposal;
+ }
+
+ internal async Task ApproveWithMinersAsync(Hash proposalId)
+ {
+ foreach (var bp in InitialCoreDataCenterKeyPairs)
+ {
+ var tester = GetParliamentContractTester(bp);
+ await tester.Approve.SendAsync(proposalId);
+ }
}
}
diff --git a/test/AElf.Contracts.Profit.Tests/ProfitContractTestBase.cs b/test/AElf.Contracts.Profit.Tests/ProfitContractTestBase.cs
index 0b857f0e49..82dbf5f5ed 100644
--- a/test/AElf.Contracts.Profit.Tests/ProfitContractTestBase.cs
+++ b/test/AElf.Contracts.Profit.Tests/ProfitContractTestBase.cs
@@ -158,6 +158,7 @@ private SystemContractDeploymentInput.Types.SystemTransactionMethodCallList
TokenName = "elf token",
TotalSupply = ProfitContractTestConstants.NativeTokenTotalSupply,
Issuer = Starter,
+ Owner = Starter,
LockWhiteList =
{
ProfitContractAddress
diff --git a/test/AElf.Contracts.Profit.Tests/ProfitTests.cs b/test/AElf.Contracts.Profit.Tests/ProfitTests.cs
index 71d52660e0..34979069da 100644
--- a/test/AElf.Contracts.Profit.Tests/ProfitTests.cs
+++ b/test/AElf.Contracts.Profit.Tests/ProfitTests.cs
@@ -1679,19 +1679,6 @@ await ProfitContractStub.ClaimProfits.SendAsync(new ClaimProfitsInput
details.Details.First().LastProfitPeriod.ShouldBe(scheme.CurrentPeriod);
}
}
-
- [Fact]
- public async Task IncreaseBackupSubsidyTotalShare_Test()
- {
- var schemeId = await CreateSchemeAsync();
- var scheme = await ProfitContractStub.GetScheme.CallAsync(schemeId);
- scheme.TotalShares.ShouldBe(0);
- await ProfitContractStub.IncreaseBackupSubsidyTotalShare.SendAsync(schemeId);
- scheme = await ProfitContractStub.GetScheme.CallAsync(schemeId);
- scheme.TotalShares.ShouldBe(1);
- var result = await ProfitContractStub.IncreaseBackupSubsidyTotalShare.SendWithExceptionAsync(schemeId);
- result.TransactionResult.Error.ShouldContain("Already increased");
- }
private async Task ContributeProfits(Hash schemeId, long amount = 100)
{
diff --git a/test/AElf.Contracts.Referendum.Tests/ReferendumContractTest.cs b/test/AElf.Contracts.Referendum.Tests/ReferendumContractTest.cs
index e4e87910a0..d22a250401 100644
--- a/test/AElf.Contracts.Referendum.Tests/ReferendumContractTest.cs
+++ b/test/AElf.Contracts.Referendum.Tests/ReferendumContractTest.cs
@@ -1,6 +1,7 @@
using System.Linq;
using System.Threading.Tasks;
using AElf.Contracts.MultiToken;
+using AElf.Contracts.Parliament;
using AElf.Cryptography.ECDSA;
using AElf.CSharp.Core.Extension;
using AElf.Kernel;
@@ -97,6 +98,7 @@ public async Task Get_Proposal_Test()
TotalSupply = 10_0000,
TokenName = "new token",
Issuer = organizationAddress,
+ Owner = organizationAddress,
IsBurnable = true
};
var proposalId = await CreateProposalAsync(DefaultSenderKeyPair, organizationAddress);
@@ -531,6 +533,17 @@ public async Task Check_Proposal_ToBeRelease()
result = await ReferendumContractStub.GetProposal.CallAsync(proposalId);
result.ToBeReleased.ShouldBeFalse();
}
+ }
+
+ [Fact]
+ public async Task Check_Proposal_ToBeRelease_Rejection()
+ {
+ var minimalApproveThreshold = 1000;
+ var minimalVoteThreshold = 1000;
+ var maximalRejectionThreshold = 1000;
+ var maximalAbstentionThreshold = 1000;
+ var organizationAddress = await CreateOrganizationAsync(minimalApproveThreshold, minimalVoteThreshold,
+ maximalAbstentionThreshold, maximalRejectionThreshold, new[] { DefaultSender });
//Rejection probability > maximalRejectionThreshold
{
var proposalId = await CreateProposalAsync(DefaultSenderKeyPair, organizationAddress);
@@ -609,7 +622,7 @@ public async Task Release_Proposal_Test()
var maximalAbstentionThreshold = 10000;
var organizationAddress = await CreateOrganizationAsync(minimalApproveThreshold, minimalVoteThreshold,
maximalAbstentionThreshold, maximalRejectionThreshold, new[] { DefaultSender });
-
+
await ApproveAndTransferCreateTokenFee(DefaultSenderKeyPair, minimalApproveThreshold, organizationAddress);
var proposalId = await CreateProposalAsync(DefaultSenderKeyPair, organizationAddress);
await ApproveAllowanceAsync(Accounts[3].KeyPair, minimalApproveThreshold, proposalId);
@@ -634,7 +647,7 @@ public async Task Release_Proposal_AlreadyReleased_Test()
var maximalAbstentionThreshold = 10000;
var organizationAddress = await CreateOrganizationAsync(minimalApproveThreshold, minimalVoteThreshold,
maximalAbstentionThreshold, maximalRejectionThreshold, new[] { DefaultSender });
-
+
await ApproveAndTransferCreateTokenFee(DefaultSenderKeyPair, minimalApproveThreshold, organizationAddress);
var proposalId = await CreateProposalAsync(DefaultSenderKeyPair, organizationAddress);
@@ -1290,6 +1303,7 @@ private CreateProposalInput GetValidCreateProposalInput(Address organizationAddr
private async Task CreateProposalAsync(ECKeyPair proposalKeyPair, Address organizationAddress,
Timestamp timestamp = null)
{
+ await PrepareCreateToken(organizationAddress);
var createInput = new CreateInput
{
Symbol = "NEW",
@@ -1297,6 +1311,7 @@ private async Task CreateProposalAsync(ECKeyPair proposalKeyPair, Address
TotalSupply = 10_0000,
TokenName = "new token",
Issuer = organizationAddress,
+ Owner = organizationAddress,
IsBurnable = true
};
var createProposalInput = new CreateProposalInput
@@ -1313,6 +1328,61 @@ private async Task CreateProposalAsync(ECKeyPair proposalKeyPair, Address
return proposal.Output;
}
+ private async Task PrepareCreateToken(Address organizationAddress)
+ {
+ var defaultParliamentAddress =
+ await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
+ var seedCollectionInfo = await TokenContractStub.GetTokenInfo.CallAsync(new GetTokenInfoInput
+ {
+ Symbol = "SEED-0"
+ });
+ await SubmitAndApproveProposalOfDefaultParliament(DefaultSenderKeyPair, ParliamentContractAddress,
+ TokenContractAddress,
+ nameof(TokenContractStub.Create), new CreateInput
+ {
+ Symbol = "SEED-0",
+ Decimals = 0,
+ IsBurnable = true,
+ TokenName = "seed Collection",
+ TotalSupply = 1,
+ Issuer = defaultParliamentAddress,
+ ExternalInfo = new ExternalInfo(),
+ Owner = defaultParliamentAddress
+ });
+
+ await SubmitAndApproveProposalOfDefaultParliament(DefaultSenderKeyPair, ParliamentContractAddress,
+ TokenContractAddress,
+ nameof(TokenContractStub.Create), new CreateInput
+ {
+ Symbol = "SEED-1",
+ Decimals = 0,
+ IsBurnable = true,
+ TokenName = "seed token" + 1,
+ TotalSupply = 1,
+ Issuer = defaultParliamentAddress,
+ ExternalInfo = new ExternalInfo
+ {
+ Value =
+ {
+ { "__seed_owned_symbol", "NEW" },
+ { "__seed_exp_time", TimestampHelper.GetUtcNow().AddDays(1).Seconds.ToString() }
+ }
+ },
+ LockWhiteList = { TokenContractAddress },
+ Owner = defaultParliamentAddress
+ });
+
+ await SubmitAndApproveProposalOfDefaultParliament(DefaultSenderKeyPair, ParliamentContractAddress,
+ TokenContractAddress,
+ nameof(TokenContractStub.Issue), new IssueInput
+ {
+ Symbol = "SEED-1",
+ Amount = 1,
+ Memo = "ddd",
+ To = organizationAddress
+ });
+ }
+
private async Task CreateReferendumProposalAsync(ECKeyPair proposalKeyPair, IMessage input,
string method, Address organizationAddress, Address toAddress)
{
@@ -1454,6 +1524,7 @@ private async Task ApproveWithMinersAsync(Hash proposalId)
approveResult.TransactionResult.Error.ShouldBeNullOrEmpty();
}
}
+
private async Task ApproveAndTransferCreateTokenFee(ECKeyPair proposalKeyPair, long minimalApproveThreshold,
Address organizationAddress)
{
@@ -1497,4 +1568,33 @@ private MethodFees GetValidMethodFees()
}
};
}
+
+ private async Task SubmitAndApproveProposalOfDefaultParliament(ECKeyPair senderKeyPair, Address parliamentAddress,
+ Address contractAddress, string methodName, IMessage message)
+ {
+ var defaultParliamentAddress =
+ await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
+
+ var proposal = new CreateProposalInput
+ {
+ OrganizationAddress = defaultParliamentAddress,
+ ContractMethodName = methodName,
+ ExpiredTime = TimestampHelper.GetUtcNow().AddHours(1),
+ Params = message.ToByteString(),
+ ToAddress = contractAddress
+ };
+ var createResult = await ParliamentContractStub.CreateProposal.SendAsync(proposal);
+ var proposalId = createResult.Output;
+ await ApproveWithMinersAsync(proposalId, parliamentAddress);
+ await ParliamentContractStub.Release.SendAsync(proposalId);
+ }
+
+ private async Task ApproveWithMinersAsync(Hash proposalId, Address parliamentAddress)
+ {
+ foreach (var bp in InitialCoreDataCenterKeyPairs)
+ {
+ var tester = GetTester(parliamentAddress, bp);
+ await tester.Approve.SendAsync(proposalId);
+ }
+ }
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.Referendum.Tests/ReferendumContractTestBase.cs b/test/AElf.Contracts.Referendum.Tests/ReferendumContractTestBase.cs
index add7e3d3fb..58d057d846 100644
--- a/test/AElf.Contracts.Referendum.Tests/ReferendumContractTestBase.cs
+++ b/test/AElf.Contracts.Referendum.Tests/ReferendumContractTestBase.cs
@@ -141,7 +141,8 @@ private SystemContractDeploymentInput.Types.SystemTransactionMethodCallList
IsBurnable = true,
TokenName = "elf token",
TotalSupply = totalSupply,
- Issuer = DefaultSender
+ Issuer = DefaultSender,
+ Owner = DefaultSender,
});
//issue default user
diff --git a/test/AElf.Contracts.TestBase/ContractTester.cs b/test/AElf.Contracts.TestBase/ContractTester.cs
index 2ac2ea3092..06520a17d2 100644
--- a/test/AElf.Contracts.TestBase/ContractTester.cs
+++ b/test/AElf.Contracts.TestBase/ContractTester.cs
@@ -710,6 +710,7 @@ public Action> GetDefaultContractTypes(Address iss
TotalSupply = totalSupply,
Decimals = 8,
Issuer = issuer,
+ Owner = issuer,
IsBurnable = true
});
tokenContractCallList.Add(nameof(TokenContract.SetPrimaryTokenSymbol),
@@ -767,6 +768,7 @@ public Action> GetSideChainSystemContract(Address
Symbol = "ELF",
Decimals = 2,
Issuer = issuer,
+ Owner = issuer,
IsBurnable = true,
TokenName = "elf token",
TotalSupply = TokenTotalSupply,
@@ -781,6 +783,7 @@ public Action> GetSideChainSystemContract(Address
Decimals = nativeTokenInfo.Decimals,
IssueChainId = nativeTokenInfo.IssueChainId,
Issuer = nativeTokenInfo.Issuer,
+ Owner = nativeTokenInfo.Issuer,
IsBurnable = nativeTokenInfo.IsBurnable,
Symbol = nativeTokenInfo.Symbol,
TokenName = nativeTokenInfo.TokenName,
@@ -796,6 +799,7 @@ public Action> GetSideChainSystemContract(Address
Decimals = 2,
IsBurnable = true,
Issuer = Address.FromPublicKey(KeyPair.PublicKey),
+ Owner = Address.FromPublicKey(KeyPair.PublicKey),
TotalSupply = 1_000_000_000,
Symbol = symbol,
TokenName = "TEST",
diff --git a/test/AElf.Contracts.TestContract.BasicFunction/BasicContract_Action.cs b/test/AElf.Contracts.TestContract.BasicFunction/BasicContract_Action.cs
index b2b539bb91..b5596c26d7 100644
--- a/test/AElf.Contracts.TestContract.BasicFunction/BasicContract_Action.cs
+++ b/test/AElf.Contracts.TestContract.BasicFunction/BasicContract_Action.cs
@@ -185,6 +185,7 @@ public override Empty CreateTokenThroughMultiToken(CreateTokenThroughMultiTokenI
Symbol = input.Symbol,
Decimals = input.Decimals,
Issuer = input.Issuer,
+ Owner = input.Issuer,
IsBurnable = input.IsBurnable,
IssueChainId = input.IssueChainId,
TokenName = input.TokenName,
diff --git a/test/AElf.Contracts.TestContract.DApp/DAppContract.cs b/test/AElf.Contracts.TestContract.DApp/DAppContract.cs
index 9e5d90337f..ec205bd134 100644
--- a/test/AElf.Contracts.TestContract.DApp/DAppContract.cs
+++ b/test/AElf.Contracts.TestContract.DApp/DAppContract.cs
@@ -197,6 +197,7 @@ private void CreateToken(Address profitReceiver, bool isLockWhiteListIncludingSe
TokenName = "DApp Token",
Decimals = DAppConstants.Decimal,
Issuer = Context.Self,
+ Owner = Context.Self,
IsBurnable = true,
TotalSupply = DAppConstants.TotalSupply,
LockWhiteList =
diff --git a/test/AElf.Contracts.TestContract.MockParliament/AElf.Contracts.TestContract.MockParliament.csproj b/test/AElf.Contracts.TestContract.MockParliament/AElf.Contracts.TestContract.MockParliament.csproj
new file mode 100644
index 0000000000..b9228e40c9
--- /dev/null
+++ b/test/AElf.Contracts.TestContract.MockParliament/AElf.Contracts.TestContract.MockParliament.csproj
@@ -0,0 +1,31 @@
+
+
+
+ net6.0
+ 1.2.0
+ AElf.Contracts.TestContract.MockParliament
+ AElf.Contracts.TestContract.MockParliament
+
+
+
+
+
+
+
+
+ Protobuf\Proto\authority_info.proto
+
+
+
+
+
+ Protobuf\Proto\test_mock_parliament_contract.proto
+
+
+
+
+
+
+
+
+
diff --git a/test/AElf.Contracts.TestContract.MockParliament/Contract.cs b/test/AElf.Contracts.TestContract.MockParliament/Contract.cs
new file mode 100644
index 0000000000..046457ca88
--- /dev/null
+++ b/test/AElf.Contracts.TestContract.MockParliament/Contract.cs
@@ -0,0 +1,19 @@
+using AElf.Types;
+using Google.Protobuf.WellKnownTypes;
+
+namespace AElf.Contracts.TestContract.MockParliament;
+
+public class Contract : MockParliamentContractContainer.MockParliamentContractBase
+{
+ public override Address GetDefaultOrganizationAddress(Empty input)
+ {
+ return State.DefaultOrganizationAddress.Value ?? new Address();
+ }
+
+ public override Empty Initialize(InitializeInput input)
+ {
+ State.DefaultOrganizationAddress.Value = input.PrivilegedProposer;
+
+ return new Empty();
+ }
+}
\ No newline at end of file
diff --git a/test/AElf.Contracts.TestContract.MockParliament/State.cs b/test/AElf.Contracts.TestContract.MockParliament/State.cs
new file mode 100644
index 0000000000..07fa208914
--- /dev/null
+++ b/test/AElf.Contracts.TestContract.MockParliament/State.cs
@@ -0,0 +1,9 @@
+using AElf.Sdk.CSharp.State;
+using AElf.Types;
+
+namespace AElf.Contracts.TestContract.MockParliament;
+
+public partial class MockParliamentContractState : ContractState
+{
+ public SingletonState DefaultOrganizationAddress { get; set; }
+}
\ No newline at end of file
diff --git a/test/AElf.Contracts.TestContract.Tests/TestContractTestBase.cs b/test/AElf.Contracts.TestContract.Tests/TestContractTestBase.cs
index 8ebd7a63e2..861a23a300 100644
--- a/test/AElf.Contracts.TestContract.Tests/TestContractTestBase.cs
+++ b/test/AElf.Contracts.TestContract.Tests/TestContractTestBase.cs
@@ -329,7 +329,8 @@ protected async Task InitializeTestContracts()
{
TokenConverterContractAddress,
TreasuryContractAddress
- }
+ },
+ Owner = DefaultSender
});
CheckResult(createResult.TransactionResult);
@@ -356,7 +357,8 @@ protected async Task InitializeTestContracts()
{
TokenConverterContractAddress,
TreasuryContractAddress
- }
+ },
+ Owner = DefaultSender
});
CheckResult(createResult.TransactionResult);
issueResult = await TokenContractStub.Issue.SendAsync(new IssueInput
diff --git a/test/AElf.Contracts.TestContract.VirtualAddress/AElf.Contracts.TestContract.VirtualAddress.csproj b/test/AElf.Contracts.TestContract.VirtualAddress/AElf.Contracts.TestContract.VirtualAddress.csproj
new file mode 100644
index 0000000000..79dacdf5f2
--- /dev/null
+++ b/test/AElf.Contracts.TestContract.VirtualAddress/AElf.Contracts.TestContract.VirtualAddress.csproj
@@ -0,0 +1,47 @@
+
+
+
+ net6.0
+ AElf.Contracts.TestContract.VirtualAddress
+ AElf.Contracts.TestContract.VirtualAddress
+ false
+
+
+
+
+
+
+
+
+ Protobuf\Proto\authority_info.proto
+
+
+
+
+
+ Protobuf\Proto\reference\election_contract.proto
+
+
+ Protobuf\Proto\reference\election_contract_impl.proto
+
+
+ Protobuf\Proto\profit_contract.proto
+
+
+ Protobuf\Proto\profit_contract_impl.proto
+
+
+
+
+
+ Protobuf\Proto\acs1.proto
+
+
+
+
+
+ Protobuf\Proto\test_virtual_address_contract.proto
+
+
+
+
diff --git a/test/AElf.Contracts.TestContract.VirtualAddress/Action.cs b/test/AElf.Contracts.TestContract.VirtualAddress/Action.cs
new file mode 100644
index 0000000000..295830ea1c
--- /dev/null
+++ b/test/AElf.Contracts.TestContract.VirtualAddress/Action.cs
@@ -0,0 +1,88 @@
+using AElf.Contracts.Election;
+using AElf.Contracts.Profit;
+using AElf.Sdk.CSharp;
+using AElf.Types;
+using Google.Protobuf;
+using Google.Protobuf.WellKnownTypes;
+
+namespace AElf.Contracts.TestContract.VirtualAddress;
+
+public partial class Action : VirtualAddressContractContainer.VirtualAddressContractBase
+{
+ public override Empty VirtualAddressVote(VirtualAddressVoteInput input)
+ {
+ Initialize();
+
+ Context.SendVirtualInline(HashHelper.ComputeFrom("test"), State.ElectionContract.Value, "Vote", new VoteMinerInput
+ {
+ CandidatePubkey = input.PubKey,
+ Amount = input.Amount,
+ EndTimestamp = input.EndTimestamp,
+ Token = input.Token
+ }.ToByteString());
+
+ return new Empty();
+ }
+
+ public override Empty VirtualAddressWithdraw(Hash input)
+ {
+ Initialize();
+
+ Context.SendVirtualInline(HashHelper.ComputeFrom("test"), State.ElectionContract.Value, "Withdraw", input.ToByteString());
+
+ return new Empty();
+ }
+
+ public override Empty VirtualAddressChangeVotingOption(VirtualAddressChangeVotingOptionInput input)
+ {
+ Initialize();
+
+ Context.SendVirtualInline(HashHelper.ComputeFrom("test"), State.ElectionContract.Value, "ChangeVotingOption", new ChangeVotingOptionInput
+ {
+ CandidatePubkey = input.PubKey,
+ VoteId = input.VoteId,
+ IsResetVotingTime = input.IsReset
+ }.ToByteString());
+
+ return new Empty();
+ }
+
+ public override Empty VirtualAddressClaimProfit(VirtualAddressClaimProfitInput input)
+ {
+ Initialize();
+
+ Context.SendVirtualInline(HashHelper.ComputeFrom("test"), State.ProfitContract.Value, "ClaimProfits", new ClaimProfitsInput
+ {
+ SchemeId = input.SchemeId,
+ Beneficiary = input.Beneficiary
+ }.ToByteString());
+
+ return new Empty();
+ }
+
+ public override Empty ForwardCall(ForwardCallInput input)
+ {
+ Context.SendVirtualInline(input.VirtualAddress, input.ContractAddress, input.MethodName, input.Args);
+ return new Empty();
+ }
+
+ public override Address GetVirtualAddress(Empty input)
+ {
+ return Context.ConvertVirtualAddressToContractAddress(HashHelper.ComputeFrom("test"));
+ }
+
+ private void Initialize()
+ {
+ if (State.ElectionContract.Value == null)
+ {
+ State.ElectionContract.Value =
+ Context.GetContractAddressByName(SmartContractConstants.ElectionContractSystemName);
+ }
+
+ if (State.ProfitContract.Value == null)
+ {
+ State.ProfitContract.Value =
+ Context.GetContractAddressByName(SmartContractConstants.ProfitContractSystemName);
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/AElf.Contracts.TestContract.VirtualAddress/Action_Fee.cs b/test/AElf.Contracts.TestContract.VirtualAddress/Action_Fee.cs
new file mode 100644
index 0000000000..4d117b11f7
--- /dev/null
+++ b/test/AElf.Contracts.TestContract.VirtualAddress/Action_Fee.cs
@@ -0,0 +1,32 @@
+using AElf.Sdk.CSharp;
+using AElf.Standards.ACS1;
+using Google.Protobuf.WellKnownTypes;
+
+namespace AElf.Contracts.TestContract.VirtualAddress;
+
+public partial class Action
+{
+ [View]
+ public override MethodFees GetMethodFee(StringValue input)
+ {
+ var methodFees = State.TransactionFees[input.Value];
+ if (methodFees != null)
+ return methodFees;
+
+ //set default tx fee
+ return new MethodFees
+ {
+ MethodName = input.Value,
+ Fees =
+ {
+ new MethodFee { Symbol = "ELF", BasicFee = 1000_0000 }
+ }
+ };
+ }
+
+ public override Empty SetMethodFee(MethodFees input)
+ {
+ State.TransactionFees[input.MethodName] = input;
+ return new Empty();
+ }
+}
\ No newline at end of file
diff --git a/test/AElf.Contracts.TestContract.VirtualAddress/ReferenceState.cs b/test/AElf.Contracts.TestContract.VirtualAddress/ReferenceState.cs
new file mode 100644
index 0000000000..e9d8ef4482
--- /dev/null
+++ b/test/AElf.Contracts.TestContract.VirtualAddress/ReferenceState.cs
@@ -0,0 +1,10 @@
+using AElf.Contracts.Election;
+using AElf.Contracts.Profit;
+
+namespace AElf.Contracts.TestContract.VirtualAddress;
+
+public partial class State
+{
+ internal ElectionContractContainer.ElectionContractReferenceState ElectionContract { get; set; }
+ internal ProfitContractContainer.ProfitContractReferenceState ProfitContract { get; set; }
+}
\ No newline at end of file
diff --git a/test/AElf.Contracts.TestContract.VirtualAddress/State.cs b/test/AElf.Contracts.TestContract.VirtualAddress/State.cs
new file mode 100644
index 0000000000..0869e1a44e
--- /dev/null
+++ b/test/AElf.Contracts.TestContract.VirtualAddress/State.cs
@@ -0,0 +1,9 @@
+using AElf.Sdk.CSharp.State;
+using AElf.Standards.ACS1;
+
+namespace AElf.Contracts.TestContract.VirtualAddress;
+
+public partial class State : ContractState
+{
+ public MappedState TransactionFees { get; set; }
+}
\ No newline at end of file
diff --git a/test/AElf.Contracts.TestContract.Vote/AElf.Contracts.TestContract.Vote.csproj b/test/AElf.Contracts.TestContract.Vote/AElf.Contracts.TestContract.Vote.csproj
new file mode 100644
index 0000000000..2924bb78db
--- /dev/null
+++ b/test/AElf.Contracts.TestContract.Vote/AElf.Contracts.TestContract.Vote.csproj
@@ -0,0 +1,29 @@
+
+
+
+ net6.0
+ 1.1.0
+
+
+
+ true
+
+
+
+
+
+
+
+
+ Protobuf\Proto\authority_info.proto
+
+
+
+
+ Protobuf\Proto\acs1.proto
+
+
+ Protobuf\Proto\test_vote_contract.proto
+
+
+
diff --git a/test/AElf.Contracts.TestContract.Vote/VoteContract.cs b/test/AElf.Contracts.TestContract.Vote/VoteContract.cs
new file mode 100644
index 0000000000..4e7ae7c700
--- /dev/null
+++ b/test/AElf.Contracts.TestContract.Vote/VoteContract.cs
@@ -0,0 +1,11 @@
+using Google.Protobuf.WellKnownTypes;
+
+namespace AElf.Contracts.TestContract.Vote;
+
+public class VoteContract : VoteContractContainer.VoteContractBase
+{
+ public override Empty AddOption(AddOptionInput input)
+ {
+ return new Empty();
+ }
+}
\ No newline at end of file
diff --git a/test/AElf.Contracts.TestContract.Vote/VoteContractState.cs b/test/AElf.Contracts.TestContract.Vote/VoteContractState.cs
new file mode 100644
index 0000000000..b7dbffd482
--- /dev/null
+++ b/test/AElf.Contracts.TestContract.Vote/VoteContractState.cs
@@ -0,0 +1,10 @@
+using AElf.Sdk.CSharp.State;
+using AElf.Types;
+using Google.Protobuf.WellKnownTypes;
+
+namespace AElf.Contracts.TestContract.Vote;
+
+public class VoteContractState : ContractState
+{
+ public MappedState State { get; set; }
+}
\ No newline at end of file
diff --git a/test/AElf.Contracts.TokenConverter.Tests/TokenConvertConnectorTest.cs b/test/AElf.Contracts.TokenConverter.Tests/TokenConvertConnectorTest.cs
index fdefbd921a..6c462e1d96 100644
--- a/test/AElf.Contracts.TokenConverter.Tests/TokenConvertConnectorTest.cs
+++ b/test/AElf.Contracts.TokenConverter.Tests/TokenConvertConnectorTest.cs
@@ -15,11 +15,6 @@ namespace AElf.Contracts.TokenConverter;
public partial class TokenConverterContractTests
{
- public TokenConverterContractTests()
- {
- AsyncHelper.RunSync(InitializeParliamentContractAsync);
- }
-
[Fact]
public async Task DefaultController_Test()
{
@@ -295,15 +290,7 @@ public async Task Set_Connector_Test()
var tokenSymbol = "TRA";
//with authority user
{
- var createTokenRet = (await TokenContractStub.Create.SendAsync(new CreateInput
- {
- Symbol = tokenSymbol,
- TokenName = "NET name",
- TotalSupply = 100_0000_0000,
- Issuer = DefaultSender,
- IsBurnable = true
- })).TransactionResult;
- createTokenRet.Status.ShouldBe(TransactionResultStatus.Mined);
+ await CreateTokenAsync(tokenSymbol);
var pairConnector = new PairConnectorParam
{
ResourceConnectorSymbol = tokenSymbol,
@@ -328,16 +315,7 @@ await ExecuteProposalForParliamentTransaction(TokenConverterContractAddress,
public async Task Update_Connector_Success_Test()
{
var token = "NETT";
- var createTokenRet = (await TokenContractStub.Create.SendAsync(new CreateInput
- {
- Symbol = token,
- TokenName = "NETT name",
- TotalSupply = 100_0000_0000,
- Issuer = DefaultSender,
- IsBurnable = true,
- LockWhiteList = { TokenConverterContractAddress }
- })).TransactionResult;
- createTokenRet.Status.ShouldBe(TransactionResultStatus.Mined);
+ await CreateTokenAsync(token);
var pairConnector = new PairConnectorParam
{
ResourceConnectorSymbol = token,
@@ -526,15 +504,17 @@ private PairConnectorParam GetLegalPairConnectorParam(string tokenSymbol, long n
private async Task CreateTokenAsync(string symbol, long totalSupply = 100_0000_0000)
{
- await TokenContractStub.Create.SendAsync(new CreateInput
- {
- Symbol = symbol,
- TokenName = symbol + " name",
- TotalSupply = totalSupply,
- Issuer = DefaultSender,
- IsBurnable = true,
- LockWhiteList = { TokenConverterContractAddress }
- });
+ await ExecuteProposalForParliamentTransaction(TokenContractAddress, nameof(TokenContractStub.Create),
+ new CreateInput
+ {
+ Symbol = symbol,
+ TokenName = symbol + " name",
+ TotalSupply = totalSupply,
+ Issuer = DefaultSender,
+ Owner = DefaultSender,
+ IsBurnable = true,
+ LockWhiteList = { TokenContractAddress, TokenConverterContractAddress }
+ });
}
private async Task AddPairConnectorAsync(string tokenSymbol)
@@ -545,59 +525,4 @@ await ExecuteProposalForParliamentTransaction(
nameof(TokenConverterContractImplContainer.TokenConverterContractImplStub.AddPairConnector),
pairConnector);
}
-
- private async Task ApproveByParliamentMembers(Hash proposalId)
- {
- foreach (var bp in InitialCoreDataCenterKeyPairs)
- {
- var tester = GetParliamentContractTester(bp);
- await tester.Approve.SendAsync(proposalId);
- }
- }
-
- private async Task CreateAndApproveProposalForParliament(Address contract,
- string method, IMessage input, Address parliamentOrganization = null)
- {
- if (parliamentOrganization == null)
- parliamentOrganization =
- await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
- var proposal = new CreateProposalInput
- {
- OrganizationAddress = parliamentOrganization,
- ContractMethodName = method,
- ExpiredTime = TimestampHelper.GetUtcNow().AddHours(1),
- Params = input.ToByteString(),
- ToAddress = contract
- };
- var createResult = await ParliamentContractStub.CreateProposal.SendAsync(proposal);
- var proposalHash = createResult.Output;
- await ApproveByParliamentMembers(proposalHash);
- return proposalHash;
- }
-
- private async Task ExecuteProposalForParliamentTransactionWithException(
- Address contract,
- string method, IMessage input, Address parliamentOrganization = null)
- {
- if (parliamentOrganization == null)
- parliamentOrganization =
- await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
- var proposalHash =
- await CreateAndApproveProposalForParliament(contract, method, input,
- parliamentOrganization);
- var releaseResult = await ParliamentContractStub.Release.SendWithExceptionAsync(proposalHash);
- return releaseResult.TransactionResult;
- }
-
- private async Task ExecuteProposalForParliamentTransaction(Address contract,
- string method, IMessage input, Address parliamentOrganization = null)
- {
- if (parliamentOrganization == null)
- parliamentOrganization =
- await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
- var proposalHash =
- await CreateAndApproveProposalForParliament(contract, method, input,
- parliamentOrganization);
- await ParliamentContractStub.Release.SendAsync(proposalHash);
- }
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.TokenConverter.Tests/TokenConverterContractTests.cs b/test/AElf.Contracts.TokenConverter.Tests/TokenConverterContractTests.cs
index 8d8bd44935..2f598d96e1 100644
--- a/test/AElf.Contracts.TokenConverter.Tests/TokenConverterContractTests.cs
+++ b/test/AElf.Contracts.TokenConverter.Tests/TokenConverterContractTests.cs
@@ -363,17 +363,18 @@ private InitializeInput GetLegalInitializeInput()
private async Task CreateRamToken()
{
- var createResult = (await TokenContractStub.Create.SendAsync(
+ await ExecuteProposalForParliamentTransaction(TokenContractAddress, nameof(TokenContractStub.Create),
new CreateInput
{
Symbol = WriteConnector.Symbol,
Decimals = 2,
IsBurnable = true,
Issuer = DefaultSender,
+ Owner = DefaultSender,
TokenName = "Write Resource",
- TotalSupply = 100_0000L
- })).TransactionResult;
- createResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ TotalSupply = 100_0000L,
+ LockWhiteList = { TokenContractAddress, TokenConverterContractAddress }
+ });
var issueResult = (await TokenContractStub.Issue.SendAsync(
new IssueInput
diff --git a/test/AElf.Contracts.TokenConverter.Tests/TokenConverterTestBase.cs b/test/AElf.Contracts.TokenConverter.Tests/TokenConverterTestBase.cs
index e453e1b0fd..3167d6a9e5 100644
--- a/test/AElf.Contracts.TokenConverter.Tests/TokenConverterTestBase.cs
+++ b/test/AElf.Contracts.TokenConverter.Tests/TokenConverterTestBase.cs
@@ -7,11 +7,15 @@
using AElf.Contracts.Treasury;
using AElf.ContractTestKit.AEDPoSExtension;
using AElf.Cryptography.ECDSA;
+using AElf.CSharp.Core.Extension;
using AElf.EconomicSystem;
+using AElf.Kernel;
using AElf.Kernel.Consensus;
using AElf.Kernel.Proposal;
using AElf.Kernel.Token;
+using AElf.Standards.ACS3;
using AElf.Types;
+using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using Volo.Abp.Threading;
@@ -30,7 +34,7 @@ public TokenConverterTestBase()
ParliamentSmartContractAddressNameProvider.Name,
ConsensusSmartContractAddressNameProvider.Name
}));
-
+ AsyncHelper.RunSync(InitializeParliamentContractAsync);
AsyncHelper.RunSync(InitializeTokenAsync);
}
@@ -47,16 +51,18 @@ protected async Task GetBalanceAsync(string symbol, Address owner)
private async Task InitializeTokenAsync()
{
- await TokenContractStub.Create.SendAsync(new CreateInput
- {
- Symbol = "ELF",
- Decimals = 2,
- IsBurnable = true,
- TokenName = "elf token",
- TotalSupply = 1000_0000_0000L,
- Issuer = DefaultSender,
- LockWhiteList = { TokenConverterContractAddress }
- });
+ await ExecuteProposalForParliamentTransaction(TokenContractAddress, nameof(TokenContractStub.Create),
+ new CreateInput
+ {
+ Symbol = "ELF",
+ Decimals = 2,
+ IsBurnable = true,
+ TokenName = "elf token",
+ TotalSupply = 1000_0000_0000L,
+ Issuer = DefaultSender,
+ Owner = DefaultSender,
+ LockWhiteList = { TokenContractAddress, TokenConverterContractAddress }
+ });
await TokenContractStub.Issue.SendAsync(new IssueInput
{
Symbol = "ELF",
@@ -94,6 +100,61 @@ private void CheckResult(TransactionResult result)
if (!string.IsNullOrEmpty(result.Error)) throw new Exception(result.Error);
}
+ protected async Task ExecuteProposalForParliamentTransaction(Address contract,
+ string method, IMessage input, Address parliamentOrganization = null)
+ {
+ if (parliamentOrganization == null)
+ parliamentOrganization =
+ await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
+ var proposalHash =
+ await CreateAndApproveProposalForParliament(contract, method, input,
+ parliamentOrganization);
+ await ParliamentContractStub.Release.SendAsync(proposalHash);
+ }
+
+ private async Task CreateAndApproveProposalForParliament(Address contract,
+ string method, IMessage input, Address parliamentOrganization = null)
+ {
+ if (parliamentOrganization == null)
+ parliamentOrganization =
+ await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
+ var proposal = new CreateProposalInput
+ {
+ OrganizationAddress = parliamentOrganization,
+ ContractMethodName = method,
+ ExpiredTime = TimestampHelper.GetUtcNow().AddHours(1),
+ Params = input.ToByteString(),
+ ToAddress = contract
+ };
+ var createResult = await ParliamentContractStub.CreateProposal.SendAsync(proposal);
+ var proposalHash = createResult.Output;
+ await ApproveByParliamentMembers(proposalHash);
+ return proposalHash;
+ }
+
+ protected async Task ExecuteProposalForParliamentTransactionWithException(
+ Address contract,
+ string method, IMessage input, Address parliamentOrganization = null)
+ {
+ if (parliamentOrganization == null)
+ parliamentOrganization =
+ await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
+ var proposalHash =
+ await CreateAndApproveProposalForParliament(contract, method, input,
+ parliamentOrganization);
+ var releaseResult = await ParliamentContractStub.Release.SendWithExceptionAsync(proposalHash);
+ return releaseResult.TransactionResult;
+ }
+
+ private async Task ApproveByParliamentMembers(Hash proposalId)
+ {
+ foreach (var bp in InitialCoreDataCenterKeyPairs)
+ {
+ var tester = GetParliamentContractTester(bp);
+ await tester.Approve.SendAsync(proposalId);
+ }
+ }
+
#region Contract Address
protected Address TokenContractAddress =>
diff --git a/test/AElf.Contracts.TokenHolder.Tests/AElf.Contracts.TokenHolder.Tests.csproj b/test/AElf.Contracts.TokenHolder.Tests/AElf.Contracts.TokenHolder.Tests.csproj
index ff8f4950ef..92957ed179 100644
--- a/test/AElf.Contracts.TokenHolder.Tests/AElf.Contracts.TokenHolder.Tests.csproj
+++ b/test/AElf.Contracts.TokenHolder.Tests/AElf.Contracts.TokenHolder.Tests.csproj
@@ -15,7 +15,7 @@
runtime; build; native; contentfiles; analyzers
-
+
all
@@ -27,15 +27,15 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -91,6 +91,9 @@
Protobuf\Proto\aedpos_contract_impl.proto
+
+ Protobuf\Proto\acs3.proto
+
Protobuf\Proto\acs4.proto
diff --git a/test/AElf.Contracts.TokenHolder.Tests/TokenHolderContractTestBase.cs b/test/AElf.Contracts.TokenHolder.Tests/TokenHolderContractTestBase.cs
index 2e4a17a843..e127c3a78b 100644
--- a/test/AElf.Contracts.TokenHolder.Tests/TokenHolderContractTestBase.cs
+++ b/test/AElf.Contracts.TokenHolder.Tests/TokenHolderContractTestBase.cs
@@ -91,6 +91,29 @@ protected void InitializeContracts()
})).Output;
TokenHolderContractStub = GetTokenHolderContractTester(StarterKeyPair);
+ //deploy parliament auth contract
+ ParliamentContractAddress = AsyncHelper.RunSync(() => GetContractZeroTester(StarterKeyPair)
+ .DeploySystemSmartContract.SendAsync(
+ new SystemContractDeploymentInput
+ {
+ Category = KernelConstants.CodeCoverageRunnerCategory,
+ Code = ByteString.CopyFrom(File.ReadAllBytes(typeof(ParliamentContract).Assembly.Location)),
+ Name = ParliamentSmartContractAddressNameProvider.Name,
+ TransactionMethodCallList = GenerateParliamentInitializationCallList()
+ })).Output;
+ ParliamentContractStub = GetParliamentContractTester(StarterKeyPair);
+
+ //deploy DApp contract
+ DAppContractAddress = AsyncHelper.RunSync(() => GetContractZeroTester(StarterKeyPair)
+ .DeploySystemSmartContract.SendAsync(
+ new SystemContractDeploymentInput
+ {
+ Category = KernelConstants.CodeCoverageRunnerCategory,
+ Code = ByteString.CopyFrom(File.ReadAllBytes(typeof(DAppContract).Assembly.Location)),
+ Name = DappSmartContractAddressNameProvider.Name
+ })).Output;
+ DAppContractStub = GetTester(DAppContractAddress, UserKeyPairs.First());
+
//deploy token contract
TokenContractAddress = AsyncHelper.RunSync(() => GetContractZeroTester(StarterKeyPair)
.DeploySystemSmartContract.SendAsync(
@@ -102,18 +125,99 @@ protected void InitializeContracts()
TransactionMethodCallList = GenerateTokenInitializationCallList()
})).Output;
TokenContractStub = GetTokenContractTester(StarterKeyPair);
-
- //deploy parliament auth contract
- ParliamentContractAddress = AsyncHelper.RunSync(() => GetContractZeroTester(StarterKeyPair)
- .DeploySystemSmartContract.SendAsync(
- new SystemContractDeploymentInput
+
+ AsyncHelper.RunSync(() => TokenContractStub.Create.SendAsync(new CreateInput
+ {
+ Symbol = "SEED-1",
+ Decimals = 0,
+ IsBurnable = true,
+ TokenName = "collection",
+ TotalSupply = 1,
+ Issuer = Starter,
+ Owner = Starter,
+ LockWhiteList =
+ {
+ TokenContractAddress
+ },
+ ExternalInfo = new ExternalInfo
+ {
+ Value =
{
- Category = KernelConstants.CodeCoverageRunnerCategory,
- Code = ByteString.CopyFrom(File.ReadAllBytes(typeof(ParliamentContract).Assembly.Location)),
- Name = ParliamentSmartContractAddressNameProvider.Name,
- TransactionMethodCallList = GenerateParliamentInitializationCallList()
- })).Output;
- ParliamentContractStub = GetParliamentContractTester(StarterKeyPair);
+ { "__seed_owned_symbol", "APP" },
+ { "__seed_exp_time", TimestampHelper.GetUtcNow().AddDays(1).Seconds.ToString() }
+ }
+ }
+ }));
+
+ AsyncHelper.RunSync(() => TokenContractStub.Create.SendAsync(new CreateInput
+ {
+ Symbol = "SEED-2",
+ Decimals = 0,
+ IsBurnable = true,
+ TokenName = "collection",
+ TotalSupply = 1,
+ Issuer = Starter,
+ Owner = Starter,
+ LockWhiteList =
+ {
+ TokenContractAddress
+ },
+ ExternalInfo = new ExternalInfo
+ {
+ Value =
+ {
+ { "__seed_owned_symbol", "AUG" },
+ { "__seed_exp_time", TimestampHelper.GetUtcNow().AddDays(1).Seconds.ToString() }
+ }
+ }
+ }));
+
+ AsyncHelper.RunSync(() => TokenContractStub.Create.SendAsync(new CreateInput
+ {
+ Symbol = "SEED-3",
+ Decimals = 0,
+ IsBurnable = true,
+ TokenName = "collection",
+ TotalSupply = 1,
+ Issuer = Starter,
+ Owner = Starter,
+ LockWhiteList =
+ {
+ TokenContractAddress
+ },
+ ExternalInfo = new ExternalInfo
+ {
+ Value =
+ {
+ { "__seed_owned_symbol", "JUN" },
+ { "__seed_exp_time", TimestampHelper.GetUtcNow().AddDays(1).Seconds.ToString() }
+ }
+ }
+ }));
+
+ AsyncHelper.RunSync(() => TokenContractStub.Issue.SendAsync(new IssueInput
+ {
+ Amount = 1,
+ Memo = "test",
+ Symbol = "SEED-1",
+ To = DAppContractAddress
+ }));
+
+ AsyncHelper.RunSync(() => TokenContractStub.Issue.SendAsync(new IssueInput
+ {
+ Amount = 1,
+ Memo = "test",
+ Symbol = "SEED-2",
+ To = Starter
+ }));
+
+ AsyncHelper.RunSync(() => TokenContractStub.Issue.SendAsync(new IssueInput
+ {
+ Amount = 1,
+ Memo = "test",
+ Symbol = "SEED-3",
+ To = Starter
+ }));
ConsensusContractAddress = AsyncHelper.RunSync(() => GetContractZeroTester(StarterKeyPair)
.DeploySystemSmartContract.SendAsync(
@@ -126,16 +230,6 @@ protected void InitializeContracts()
})).Output;
AEDPoSContractStub = GetConsensusContractTester(StarterKeyPair);
- //deploy DApp contract
- DAppContractAddress = AsyncHelper.RunSync(() => GetContractZeroTester(StarterKeyPair)
- .DeploySystemSmartContract.SendAsync(
- new SystemContractDeploymentInput
- {
- Category = KernelConstants.CodeCoverageRunnerCategory,
- Code = ByteString.CopyFrom(File.ReadAllBytes(typeof(DAppContract).Assembly.Location)),
- Name = DappSmartContractAddressNameProvider.Name
- })).Output;
- DAppContractStub = GetTester(DAppContractAddress, UserKeyPairs.First());
AsyncHelper.RunSync(TransferToContract);
AsyncHelper.RunSync(async () =>
{
@@ -198,6 +292,7 @@ private SystemContractDeploymentInput.Types.SystemTransactionMethodCallList
TokenName = "elf token",
TotalSupply = TokenHolderContractTestConstants.NativeTokenTotalSupply,
Issuer = Starter,
+ Owner = Starter,
LockWhiteList =
{
ProfitContractAddress,
@@ -222,6 +317,17 @@ private SystemContractDeploymentInput.Types.SystemTransactionMethodCallList
To = Address.FromPublicKey(creatorKeyPair.PublicKey),
Memo = "set voters few amount for voting."
}));
+
+ tokenContractCallList.Add(nameof(TokenContract.Create), new CreateInput
+ {
+ Symbol = "SEED-0",
+ Decimals = 0,
+ IsBurnable = true,
+ TokenName = "collection",
+ TotalSupply = 1,
+ Issuer = Starter,
+ Owner = Starter,
+ });
return tokenContractCallList;
}
@@ -286,7 +392,7 @@ protected async Task ApproveWithMinersAsync(Hash proposalId)
approveResult.TransactionResult.Error.ShouldBeNullOrEmpty();
}
}
-
+
private async Task TransferToContract()
{
await TokenContractStub.Transfer.SendAsync(new TransferInput
diff --git a/test/AElf.Contracts.TokenHolder.Tests/TokenHolderTests.cs b/test/AElf.Contracts.TokenHolder.Tests/TokenHolderTests.cs
index 959bc2cb56..68698e8177 100644
--- a/test/AElf.Contracts.TokenHolder.Tests/TokenHolderTests.cs
+++ b/test/AElf.Contracts.TokenHolder.Tests/TokenHolderTests.cs
@@ -504,6 +504,7 @@ await TokenContractStub.Create.SendAsync(new CreateInput
TokenName = symbol + " name",
TotalSupply = totalSupply,
Issuer = Starter,
+ Owner = Starter,
LockWhiteList = { ProfitContractAddress }
});
await TokenContractStub.Issue.SendAsync(new IssueInput
diff --git a/test/AElf.Contracts.Vote.Tests/AElf.Contracts.Vote.Tests.csproj b/test/AElf.Contracts.Vote.Tests/AElf.Contracts.Vote.Tests.csproj
index 896f50b0ab..5ad16fa9b5 100644
--- a/test/AElf.Contracts.Vote.Tests/AElf.Contracts.Vote.Tests.csproj
+++ b/test/AElf.Contracts.Vote.Tests/AElf.Contracts.Vote.Tests.csproj
@@ -34,6 +34,11 @@
+
+ false
+ Contract
+ PreserveNewest
+
@@ -81,5 +86,8 @@
Protobuf\Proto\aedpos_contract_impl.proto
+
+ Protobuf\Proto\test_virtual_address_contract.proto
+
diff --git a/test/AElf.Contracts.Vote.Tests/BVT/BasicTests.cs b/test/AElf.Contracts.Vote.Tests/BVT/BasicTests.cs
index a4b112bf30..c7ca327187 100644
--- a/test/AElf.Contracts.Vote.Tests/BVT/BasicTests.cs
+++ b/test/AElf.Contracts.Vote.Tests/BVT/BasicTests.cs
@@ -2,10 +2,13 @@
using System.Text;
using System.Threading.Tasks;
using AElf.Contracts.MultiToken;
+using AElf.Contracts.TestContract.VirtualAddress;
using AElf.CSharp.Core;
using AElf.CSharp.Core.Extension;
using AElf.Kernel;
using AElf.Types;
+using Google.Protobuf;
+using Google.Protobuf.WellKnownTypes;
using Shouldly;
using Xunit;
@@ -661,4 +664,77 @@ public async Task VoteContract_GetVotingIds_Test()
});
voteIds.ActiveVotes.Count.ShouldBe(1);
}
+
+ [Fact]
+ public async Task Vote_VirtualAddress_Success()
+ {
+ var registerItem = await RegisterVotingItemAsync(100, 3, true, DefaultSender, 1);
+ var voteItemId = registerItem.VotingItemId;
+ var voter = await VirtualAddressContractStub.GetVirtualAddress.CallAsync(new Empty());
+ var voteAmount = 100;
+ await TokenContractStub.Transfer.SendAsync(new TransferInput
+ {
+ Symbol = TestTokenSymbol,
+ Amount = 1000,
+ To = voter,
+ Memo = "transfer token to voter"
+ });
+ var beforeVoteBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = TestTokenSymbol,
+ Owner = voter
+ });
+ var sendResult = await VirtualAddressContractStub.ForwardCall.SendAsync(new ForwardCallInput
+ {
+ ContractAddress = VoteContractAddress,
+ MethodName = "Vote",
+ VirtualAddress = HashHelper.ComputeFrom("test"),
+ Args = (new VoteInput
+ {
+ VotingItemId = voteItemId,
+ Option = registerItem.Options[1],
+ Amount = voteAmount
+ }).ToByteString()
+ });
+
+ sendResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ var voteResult = await VoteContractStub.GetVotingResult.CallAsync(new GetVotingResultInput
+ {
+ SnapshotNumber = 1,
+ VotingItemId = voteItemId
+ });
+ voteResult.Results[registerItem.Options[1]].ShouldBe(voteAmount);
+ voteResult.VotesAmount.ShouldBe(voteAmount);
+ voteResult.VotersCount.ShouldBe(1);
+ var afterVoteBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = TestTokenSymbol,
+ Owner = voter
+ });
+ beforeVoteBalance.Balance.Sub(afterVoteBalance.Balance).ShouldBe(voteAmount);
+ var voteItems = await VoteContractStub.GetVotedItems.CallAsync(voter);
+ voteItems.VotedItemVoteIds.Count.ShouldBe(1);
+
+ var votingIds = await VoteContractStub.GetVotingIds.CallAsync(new GetVotingIdsInput
+ {
+ Voter = voter,
+ VotingItemId = voteItemId
+ });
+ var currentVoteId = votingIds.ActiveVotes.First();
+
+ sendResult = await VirtualAddressContractStub.ForwardCall.SendAsync(new ForwardCallInput
+ {
+ ContractAddress = VoteContractAddress,
+ MethodName = "Withdraw",
+ VirtualAddress = HashHelper.ComputeFrom("test"),
+ Args = (new WithdrawInput
+ {
+ VoteId = currentVoteId
+ }).ToByteString()
+ });
+ sendResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+
+ var afterWithdrawBalance = GetUserBalance(voter);
+ afterWithdrawBalance.ShouldBe(beforeVoteBalance.Balance);
+ }
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.Vote.Tests/VoteContractTestBase.cs b/test/AElf.Contracts.Vote.Tests/VoteContractTestBase.cs
index 779aaa37b1..e07dee28f0 100644
--- a/test/AElf.Contracts.Vote.Tests/VoteContractTestBase.cs
+++ b/test/AElf.Contracts.Vote.Tests/VoteContractTestBase.cs
@@ -4,6 +4,7 @@
using AElf.Contracts.Consensus.AEDPoS;
using AElf.Contracts.MultiToken;
using AElf.Contracts.Parliament;
+using AElf.Contracts.TestContract.VirtualAddress;
using AElf.ContractTestKit;
using AElf.Cryptography.ECDSA;
using AElf.GovernmentSystem;
@@ -32,11 +33,13 @@ public class VoteContractTestBase : ContractTestBase
protected Address ParliamentContractAddress { get; set; }
protected new Address ContractZeroAddress => ContractAddressService.GetZeroSmartContractAddress();
protected Address ConsensusContractAddress { get; set; }
+ protected Address VirtualAddressContractAddress { get; set; }
internal ACS0Container.ACS0Stub BasicContractZeroStub { get; set; }
internal TokenContractContainer.TokenContractStub TokenContractStub { get; set; }
internal VoteContractImplContainer.VoteContractImplStub VoteContractStub { get; set; }
internal ParliamentContractImplContainer.ParliamentContractImplStub ParliamentContractStub { get; set; }
internal AEDPoSContractImplContainer.AEDPoSContractImplStub AEDPoSContractStub { get; set; }
+ internal VirtualAddressContractContainer.VirtualAddressContractStub VirtualAddressContractStub { get; set; }
protected void InitializeContracts()
{
@@ -88,6 +91,14 @@ protected void InitializeContracts()
TransactionMethodCallList = GenerateConsensusInitializationCallList()
})).Output;
AEDPoSContractStub = GetConsensusContractTester(DefaultSenderKeyPair);
+
+ VirtualAddressContractAddress = AsyncHelper.RunSync(async () =>
+ await DeployContractAsync(
+ KernelConstants.CodeCoverageRunnerCategory,
+ Codes.Single(kv => kv.Key.EndsWith("VirtualAddress")).Value,
+ HashHelper.ComputeFrom("AElf.Contracts.TestContract.VirtualAddress"),
+ DefaultSenderKeyPair));
+ VirtualAddressContractStub = GetTester(VirtualAddressContractAddress, DefaultSenderKeyPair);
}
internal ACS0Container.ACS0Stub GetContractZeroTester(ECKeyPair keyPair)
@@ -134,6 +145,7 @@ private SystemContractDeploymentInput.Types.SystemTransactionMethodCallList Gene
TokenName = "elf token for testing",
TotalSupply = totalSupply,
Issuer = DefaultSender,
+ Owner = DefaultSender,
LockWhiteList =
{
VoteContractAddress
diff --git a/test/AElf.Cryptography.Tests/AElf.Cryptography.Tests.csproj b/test/AElf.Cryptography.Tests/AElf.Cryptography.Tests.csproj
index b42e0e1bd3..7ef8543522 100644
--- a/test/AElf.Cryptography.Tests/AElf.Cryptography.Tests.csproj
+++ b/test/AElf.Cryptography.Tests/AElf.Cryptography.Tests.csproj
@@ -9,18 +9,22 @@
runtime; build; native; contentfiles; analyzers
-
+
+
- all
- runtime; build; native; contentfiles; analyzers
-
+ all
+ runtime; build; native; contentfiles; analyzers
+
- all
- runtime; build; native; contentfiles; analyzers
-
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+
+
-
+
\ No newline at end of file
diff --git a/test/AElf.Cryptography.Tests/AssemblyInfo.cs b/test/AElf.Cryptography.Tests/AssemblyInfo.cs
new file mode 100644
index 0000000000..41a898e37e
--- /dev/null
+++ b/test/AElf.Cryptography.Tests/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+using Xunit;
+
+[assembly: CollectionBehavior(DisableTestParallelization = true)]
\ No newline at end of file
diff --git a/test/AElf.Cryptography.Tests/CryptoHelperTests.cs b/test/AElf.Cryptography.Tests/CryptoHelperTests.cs
index 0a5578c15f..7ec4e7c59e 100644
--- a/test/AElf.Cryptography.Tests/CryptoHelperTests.cs
+++ b/test/AElf.Cryptography.Tests/CryptoHelperTests.cs
@@ -1,6 +1,8 @@
using System;
using System.Text;
using AElf.Cryptography.Exceptions;
+using AElf.Types;
+using Org.BouncyCastle.Utilities.Encoders;
using Shouldly;
using Virgil.Crypto;
using Xunit;
@@ -132,4 +134,16 @@ public void ExceptionTest()
Should.Throw(() => throw new SignatureOperationException(message));
Should.Throw(() => throw new InvalidKeyPairException(message, new Exception()));
}
+
+ [Fact]
+ public void VrfTest()
+ {
+ var key = CryptoHelper.FromPrivateKey(
+ ByteArrayHelper.HexStringToByteArray("5945c176c4269dc2aa7daf7078bc63b952832e880da66e5f2237cdf79bc59c5f"));
+ var alpha = "5cf8151010716e40e5349ad02821da605df22e9ac95450c7e35f04c720fd4db5";
+ var alphaBytes = Hash.LoadFromHex(alpha).ToByteArray();
+ var pi = CryptoHelper.ECVrfProve(key, alphaBytes);
+ var beta = CryptoHelper.ECVrfVerify(key.PublicKey, alphaBytes, pi);
+ beta.ToHex().ShouldBe("43765915e86c205f0c28b4d22e157b8474add7faf890a3aa2a88df756651523f");
+ }
}
\ No newline at end of file
diff --git a/test/AElf.Cryptography.Tests/ECVRF/VRFTests.cs b/test/AElf.Cryptography.Tests/ECVRF/VRFTests.cs
new file mode 100644
index 0000000000..b9ac5f784c
--- /dev/null
+++ b/test/AElf.Cryptography.Tests/ECVRF/VRFTests.cs
@@ -0,0 +1,125 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using AElf.Cryptography.Core;
+using AElf.Cryptography.ECDSA;
+using AElf.Cryptography.ECVRF;
+using Secp256k1Net;
+using Xunit;
+
+namespace AElf.Cryptography.Tests.ECVRF;
+
+public class VRFTests
+{
+ public class TestVector
+ {
+ [JsonPropertyName("sk")]
+ public string Sk { get; set; }
+
+ [JsonPropertyName("pk")]
+ public string Pk { get; set; }
+
+ [JsonPropertyName("alpha")]
+ public string Alpha { get; set; }
+
+ [JsonPropertyName("beta")]
+ public string Beta { get; set; }
+
+ [JsonPropertyName("pi")]
+ public string Pi { get; set; }
+ }
+
+ [Fact]
+ public void HashToCurveTryAndIncrement_Test()
+ {
+ var pkSerialized = Convert.FromHexString("0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6");
+ var alpha = Encoding.ASCII.GetBytes("sample");
+ var expectedHashPoint = Convert.FromHexString("027AD7D4C3A454D9ECC905F1E5436A328F2A106A2606EC4B44111CF9DC72A5B9FF");
+
+ using var curve = new Secp256k1Curve();
+ var cfg = new VrfConfig( 0xfe, ECParameters.Curve);
+ var vrf = new Vrf(cfg);
+ var output = vrf.HashToCurveTryAndIncrement(curve.DeserializePoint( pkSerialized), alpha);
+ var outputSerialized = curve.SerializePoint(output, true);
+ Assert.Equal(outputSerialized, expectedHashPoint);
+ }
+
+ [Fact]
+ public void Prove_Test()
+ {
+ var path = Path.Combine( Directory.GetCurrentDirectory(), "secp256_k1_sha256_tai.json");
+ var text = File.ReadAllText(path);
+ var vectors = JsonSerializer.Deserialize>(text);
+ using var secp256k1 = new Secp256k1();
+ foreach (var vector in vectors)
+ {
+ var sk = AddLeadingZeros(Convert.FromHexString(vector.Sk));
+ var kp = CryptoHelper.FromPrivateKey(sk);
+ var alpha = Convert.FromHexString(vector.Alpha);
+ var expectedPi = Convert.FromHexString(vector.Pi);
+ var cfg = new VrfConfig( 0xfe, ECParameters.Curve);
+ var vrf = new Vrf(cfg);
+ var pi = vrf.Prove(kp, alpha);
+ Assert.Equal(expectedPi, pi);
+ }
+ }
+
+ [Fact]
+ public void Verify_Test()
+ {
+ var c = ECParameters.Curve;
+ var path = Path.Combine( Directory.GetCurrentDirectory(), "secp256_k1_sha256_tai.json");
+ var text = File.ReadAllText(path);
+ var vectors = JsonSerializer.Deserialize>(text);
+ using var secp256k1 = new Secp256k1();
+ foreach (var vector in vectors)
+ {
+ var pk =Convert.FromHexString(vector.Pk);
+ var alpha = Convert.FromHexString(vector.Alpha);
+ var pi = Convert.FromHexString(vector.Pi);
+ var expectedBeta = Convert.FromHexString(vector.Beta);
+ var cfg = new VrfConfig( 0xfe, ECParameters.Curve);
+ var vrf = new Vrf(cfg);
+ var beta = vrf.Verify(pk, alpha, pi);
+ Assert.Equal(expectedBeta, beta);
+ }
+ }
+
+ [Fact]
+ public void Verify_BadMessageFailsVerification_Test()
+ {
+ var path = Path.Combine( Directory.GetCurrentDirectory(), "secp256_k1_sha256_tai.json");
+ var text = File.ReadAllText(path);
+ var vectors = JsonSerializer.Deserialize>(text);
+ using var secp256k1 = new Secp256k1();
+ foreach (var vector in vectors)
+ {
+ var pk =Convert.FromHexString(vector.Pk);
+ var alpha = Encoding.ASCII.GetBytes("this is a wrong message");
+ var pi = Convert.FromHexString(vector.Pi);
+ var cfg = new VrfConfig( 0xfe, ECParameters.Curve);
+ var vrf = new Vrf(cfg);
+ Assert.Throws(() => vrf.Verify(pk, alpha, pi));
+ }
+ }
+ private byte[] AddLeadingZeros(byte[] sk)
+ {
+ if (sk.Length < 32)
+ {
+ var output = new byte[32];
+ var zeroBytesLength = 32 - sk.Length;
+ for (int i = zeroBytesLength - 1; i >= 0; i--)
+ {
+ output[i] = 0;
+ }
+ Buffer.BlockCopy(sk, 0, output, zeroBytesLength, sk.Length);
+ return output;
+ }
+
+ return sk;
+
+ }
+}
\ No newline at end of file
diff --git a/test/AElf.Cryptography.Tests/secp256_k1_sha256_tai.json b/test/AElf.Cryptography.Tests/secp256_k1_sha256_tai.json
new file mode 100644
index 0000000000..40900f6b17
--- /dev/null
+++ b/test/AElf.Cryptography.Tests/secp256_k1_sha256_tai.json
@@ -0,0 +1,324 @@
+[
+ {
+ "beta": "612065e309e937ef46c2ef04d5886b9c6efd2991ac484ec64a9b014366fc5d81",
+ "alpha": "73616d706c65",
+ "pi": "031f4dbca087a1972d04a07a779b7df1caa99e0f5db2aa21f3aecc4f9e10e85d08748c9fbe6b95d17359707bfb8e8ab0c93ba0c515333adcb8b64f372c535e115ccf66ebf5abe6fadb01b5efb37c0a0ec9",
+ "sk": "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721",
+ "pk": "032c8c31fc9f990c6b55e3865a184a4ce50e09481f2eaeb3e60ec1cea13a6ae645"
+ },
+ {
+ "beta": "00acd42d48046e13552f54919286c2085aec6fb874854d036f66ad572c99e7ab",
+ "alpha": "73616d706c65",
+ "pi": "029a2df6ca1d5f734945fb6847669f839eb9ecf127fa8314e5a6a5c4695c3f4d159009b3741cdec6b0d7c70e3aae6b82aeb1aad555499bd6ce10b35fa230079e6fa752e8d4755ffd285aef5133dad7a64b",
+ "sk": "01",
+ "pk": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
+ },
+ {
+ "beta": "c355718640883112731fce0b5dd97c34492d226280654dcf0ada1d6b32e3384b",
+ "alpha": "73616d706c65",
+ "pi": "0205c5a6ed80f7ffbf9f47583e873717e86c8405349266745a0504ea7ca68876ce6afe0e3cccfc7bba83a6d16771d80e26a46ad25be631869d6f60a34c12a19b868815182657288f57afb91166ceed3cc5",
+ "sk": "02",
+ "pk": "02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5"
+ },
+ {
+ "beta": "09a93f6e8a6037db146d862eec33f56c8053bb4fda309f8ecbcbe04592aabd37",
+ "alpha": "73616d706c65",
+ "pi": "02a14b92076becc501b9ac761c18cacd792e0b30ad2b6907e1273dbe3762a9d29cf97fe3a904d2123ef98030a929ea91b40f1d5f78d9eb09c85ee2caa962b17de41abd4cf6be036e90c9826ae4e6e3673a",
+ "sk": "03",
+ "pk": "02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9"
+ },
+ {
+ "beta": "5a0bce08f650d5ef80b0254ee814360e1f2c944a6c2b15e3171374f362cd92b4",
+ "alpha": "73616d706c65",
+ "pi": "03a3ca50b6f1873b8ca55348d0c62b0a2fd774aa9b96d1061c0917d6f9da5fe560dcddbda349d2db15751c965baf88ddb67075b5a441400c5ef85d9dffd6a16833993af6f05901c2421210d72d114c4ba0",
+ "sk": "04",
+ "pk": "02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13"
+ },
+ {
+ "beta": "e06dc093da223b40225633628c94a0bf909a3bb19a2f838932b4627f740354a1",
+ "alpha": "73616d706c65",
+ "pi": "030b4806f7f7398ba03951990740243d3f84a0815d85e2be439ee42bd8f249bd44e56800354296f9c05d30e06966009baf98c963028070217f28c0a298f9ecd56726bbc7c4faf1c62691972bfbc9fbd684",
+ "sk": "05",
+ "pk": "022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4"
+ },
+ {
+ "beta": "811a4fe231758d65b9b20d436a19256765776c812966032b16ce2b21e5c69be7",
+ "alpha": "73616d706c65",
+ "pi": "02f0fdc752a0c63cae4d33f65af4167a7a8b04711d840230df0d211ee3d6e2a2ad66625f4d9db7798ab664bb2da77736db6c9b7828cd8310a2e5f677224e1676afbb731cf92018a49c0452d1080aac5f3a",
+ "sk": "06",
+ "pk": "03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556"
+ },
+ {
+ "beta": "0b772c54b2125194bd26b7e3ce2c4606043f65d99d3c65aef6e3b61dffd20aae",
+ "alpha": "73616d706c65",
+ "pi": "036e041791df3880003115548bf1c491700133a23fb6c1edbef6a23f7dd67c05d5e227f496df589bdd68ffc28fb00246681abb9399a4207fbf42c2a64fa47615b4a64dc25cf0f6bc368353bfb25f63c95b",
+ "sk": "07",
+ "pk": "025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc"
+ },
+ {
+ "beta": "8f7729e4288e7630b358a6cef560479f0e441926ae0fa6a3a96f17b63b3d1fb8",
+ "alpha": "73616d706c65",
+ "pi": "02b5a04c6340c0d09b26da8f75c7713ed871e9f673bb87c00ee0e76e8045faad9ece28cfdbc41eab04205963c3252b7229d94793491e4a7f48e09c2d85b3ee2a1131a27b670b07c016dc00e4d8f3daa242",
+ "sk": "08",
+ "pk": "022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01"
+ },
+ {
+ "beta": "ce465b7e061bae415e10d8aafd32d92e2f499d959632fe5983cb0b2d4ee7b3b5",
+ "alpha": "73616d706c65",
+ "pi": "02cf1639991c8eb219993f1b9921a413e2ebc72d7b533ab952c92188b9b4ee2bd8cd5417a75c80d3022a3719297b2699b958d27e5e9fe03c8fc96766234fa497bee8287a76f6db22ff482cec9505e51a5f",
+ "sk": "09",
+ "pk": "03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe"
+ },
+ {
+ "beta": "941b5f76d95772045e824e30d85106a4a3b5920b901e178d3f62ec8e473ccf69",
+ "alpha": "73616d706c65",
+ "pi": "034e371e26303b9deb6f650f8faee60a2673b2bfef5b5a9af066aca5e7c12695becd27149218141ceb7f7e58da293679388c3b7b5109ec360a1f50decb1fa89c11b19476f5b2786ecba75f3642d942ba31",
+ "sk": "0a",
+ "pk": "03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7"
+ },
+ {
+ "beta": "79403a19944c3516d102cfa42cd5dd3f16c5c9bd457bf0659e2305374af3dccd",
+ "alpha": "73616d706c65",
+ "pi": "0384e3011d9e8235de77c211c0e57b0ed4bbffbe4b1d1a946278d13943be6c4280206842bfc58d564262a3214cfab3098d2887923eb659ff543aaa9c48d821acf1198bde5d824d27e9a9a6c2f84c6bdfdb",
+ "sk": "0b",
+ "pk": "03774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb"
+ },
+ {
+ "beta": "746ca26b7c90df37d309ecce42757e6bf9423ad31211a02e8d9d86aea72f2f3a",
+ "alpha": "73616d706c65",
+ "pi": "03ad49eb72e2c7789d851c7bf2a3137cee17ab304ae7acb7b22739c5aae48eb339199381d85ae4654b2f5488499b4d3a13d6055ca740de70bb6d9b2c0cb962d873e13cd1d1d1c0c4eef9f9809f88e36fc0",
+ "sk": "0c",
+ "pk": "03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a"
+ },
+ {
+ "beta": "51096a3de69492e852477271a77a5b95de5a0cc2fc43128177b9a85e3184318d",
+ "alpha": "73616d706c65",
+ "pi": "038be9f8885740d6a336f0ec8249ec010f99fb4f0e42f09804c6f98f0be907327419f8249ebc3fb6fb372402893c55422987d9d36f6dfbdc7cfa88fb75dca13b095f412a1d82b358b1d17406991af576e4",
+ "sk": "0d",
+ "pk": "03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8"
+ },
+ {
+ "beta": "b3a048bc1682c3d5ba4d79a951b38f6d9729a328afb38fdd22c5f17247eeb642",
+ "alpha": "73616d706c65",
+ "pi": "0354a5641699f62565bec88e75ed465c052f655048a2de85ae39f32e968a80faeb6e21ac4919dc0710e1f1a76184988926a2b354c52cf1ca8529157aa5574c385b86def3a76a7cb9e0d0a11227bc651dac",
+ "sk": "0e",
+ "pk": "03499fdf9e895e719cfd64e67f07d38e3226aa7b63678949e6e49b241a60e823e4"
+ },
+ {
+ "beta": "eb5c23bc8773fa4c83ef3bf88bf63aceffe6b042e220d8826db222dc55f915fe",
+ "alpha": "73616d706c65",
+ "pi": "0398f53f2ed4d687e6a65eaf7ce4d63e99e2db78a12302c782ffe6012737eb2d10257f7a86288479153dafa74c14092fd5acc60c953f225840ee6c92ec67106a979ead5f8c12142373b119190a012ac780",
+ "sk": "0f",
+ "pk": "02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e"
+ },
+ {
+ "beta": "e96f1bab42d66b32d2fb8ea1e4655808881cd9f208279a0757ef990575e7adc0",
+ "alpha": "73616d706c65",
+ "pi": "024ca2c0b270a6c632cade38ff097d66de362c54064e847fd96bd4067b71028db4ead3e112b4cc78b826165d6fde084924f58ae74f69c4542d68cdd5a33e03d5bd2e7fc5f5fda4c9e3d157fbb213fddd3d",
+ "sk": "10",
+ "pk": "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a"
+ },
+ {
+ "beta": "dbfeac68bfc25d1fd3f9d0bfe093edfef9e90c1b4d2940ac961c1d08ba66deb4",
+ "alpha": "73616d706c65",
+ "pi": "028594a13f389fbb3618bb5db54059ea673f087d7193ed8513d1abc7f3a5228d0e99a976d08666bdb46b287ec41945de29cce12c2dac0ba226ef3ef383a0fba8e138b415816c5243af66ef5a51244d9616",
+ "sk": "11",
+ "pk": "03defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34"
+ },
+ {
+ "beta": "87a0ff6de5a282746082ed187abc29f534c1ee4f641e604c7d241fea5155b2a2",
+ "alpha": "73616d706c65",
+ "pi": "03e9593d98552a6e3c3f45a8a566b4d2de9bd5ff1837b4ca91655dc6e91d59fb5b335fd59c15668b371093ee81df275c876761ebcbd60fa8127c7e601f99ce340a3ae8c00864c0e38ebe749e566c151240",
+ "sk": "12",
+ "pk": "025601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7cc"
+ },
+ {
+ "beta": "32306c22ad369a6e0fd638f503c0dbf674cd9d66b5da0a8c83c1d78157814f90",
+ "alpha": "73616d706c65",
+ "pi": "02833a4a802ec7f90b91dc59cfc8138669d2e6ec3f933c4fc7e44389a5e02c6032816f05729899c003ae77025e22c703809f8ee1b35d04d250800c7e90533dc4f29b3667065fc2cae0cc3cd356962ac62a",
+ "sk": "13",
+ "pk": "022b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6c"
+ },
+ {
+ "beta": "4e853d2b79f1d2dd8e23be493efa8c685afc30198070aa5acbc53fddcace9aa9",
+ "alpha": "73616d706c65",
+ "pi": "022d2bb6961468e5a3aadae02157e584a4d45f58121185cafa11b93fae6eb4a4604d03e431646fb1ee06c04e562cbd0e7d8c4fc01bc8dc0ca0f7f5d4e138be2963f6ab25843a12dd6c5e34cfda1ecabf04",
+ "sk": "14",
+ "pk": "024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97"
+ },
+ {
+ "beta": "642a4819a8e8e5739cc0f4bd5221d641774f2d33b75007c4de61f4f2089df92c",
+ "alpha": "73616d706c65",
+ "pi": "02570056bade9dc5204721d0ecd39906a72468d027dfa1a896b8f6a88d50fc5526f7afb112bb95a2e13f326cbf1c8de77b7596195575b4dd712edbfd96acafdcbc0fa1dfae4041bb64d8e25b276426ea5a",
+ "sk": "018ebbb95eed0e13",
+ "pk": "02a90cc3d3f3e146daadfc74ca1372207cb4b725ae708cef713a98edd73d99ef29"
+ },
+ {
+ "beta": "b042e27b4d0e1f1a1c8ec7d4c2c0b2ae988d4cbc526d1ffb11b0087bea97a630",
+ "alpha": "73616d706c65",
+ "pi": "02b87402d5f26e06c14a3136a6c868316d2a2d413d5ef2ef91cae3625d57e87ea326b2bb5f67e4fe3f5c65df958d1ecd7a9bebea344b1facd08fbc7512701bcababbc39c410d9d1c0980e688feada47468",
+ "sk": "159d893d4cdd747246cdca43590e13",
+ "pk": "03e5a2636bcfd412ebf36ec45b19bfb68a1bc5f8632e678132b885f7df99c5e9b3"
+ },
+ {
+ "beta": "3a36fc2ff539e516897c53d61951209dcac171500ed79692434a28e0cb9c3272",
+ "alpha": "73616d706c65",
+ "pi": "02e111fc96dd022c02f45df180c3707d5a48a5eb669aad2f7b45345b5f95a38f68b82b8cfa5dee906023fe4c2a15723636e29c8fc8d65ade1620b0d6453331f0237f632e89f0352fd25662d5630b3a6034",
+ "sk": "3fffffffffffffffffffffffffffffffaeabb739abd2280eeff497a3340d9050",
+ "pk": "03a6b594b38fb3e77c6edf78161fade2041f4e09fd8497db776e546c41567feb3c"
+ },
+ {
+ "beta": "c6e3b662984301fc84c5eb2f5c0f435aee2975a731e6707bb9e50113e4bc2809",
+ "alpha": "73616d706c65",
+ "pi": "023a435fc5fab74b0b33eeb7c62447efc323e6e33a19657e7a0a473451b885fe841f28b91f43834ab659f26ea94d9dbca325192c45589afc1415e508b72247c64e385d3f9aa13c2e571d252335b8f63a3e",
+ "sk": "7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0",
+ "pk": "0300000000000000000000003b78ce563f89a0ed9414f5aa28ad0d96d6795f9c63"
+ },
+ {
+ "beta": "a25353782f363555d90c822a347151272d364103aa49513105bcc247287ff6a9",
+ "alpha": "73616d706c65",
+ "pi": "02f769ca0cb1a96046265c19d5ef44deade0eb42a6aab094c7fde5bcdae09455db2ba3ffa7e72d01ead1fedc0162507c5d8ccbde61e09cd533b807404b75a4acb8573881f86abbf41bc0877acb3362604f",
+ "sk": "bfffffffffffffffffffffffffffffff0c0325ad0376782ccfddc6e99c28b0f0",
+ "pk": "02e24ce4beee294aa6350faa67512b99d388693ae4e7f53d19882a6ea169fc1ce1"
+ },
+ {
+ "beta": "9731f862d34587fb91521d785a30ff57188c57efd4b55239199ae4ed31bcebf8",
+ "alpha": "73616d706c65",
+ "pi": "02d196a5eb787d5d8a33247607d78d5a48164ac4d899dba33cb3a5f68032124ba1b2221b96ae997d450ddd8e5863a0cc7cf1b3f50431aa6031b6807396edfab5d1f5812c7e8d40f157028afb7aa51a41d5",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036412d",
+ "pk": "034ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97"
+ },
+ {
+ "beta": "54c8f3e98a8a8e5b77d327cdb7a71e5959996b5619972a8b472d7a3799a79387",
+ "alpha": "73616d706c65",
+ "pi": "0391aeaecb887e9d6f0c0f64d20f28acbe687bffabaaea0ff5237f236693eb5b56c88099425415cd9d242c70249f7abb8958a327ad341b4fca735f8ba61b57c9735252b72afab7e0cb6e49c9436366e800",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036412e",
+ "pk": "032b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6c"
+ },
+ {
+ "beta": "f9fba571cb27776c07d2bc42d670952e1965357942eca3edb5f80e28bc9aaed0",
+ "alpha": "73616d706c65",
+ "pi": "03b9ffede3d97b9753f8f31cd5d56442c525a5bccc2de1fc547886ee08bca9b4f3c1d44da0826ddfd763801c42875d41deeae99422c0e9e6a97e07e2689f58289bffe499069785dcffa4ff93a5b1e15856",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036412f",
+ "pk": "035601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7cc"
+ },
+ {
+ "beta": "c66931ad96cb4e1a44202fcd7882089b1cf77b07c426d292e0e15deca5c1b027",
+ "alpha": "73616d706c65",
+ "pi": "03ca01e6d80f99bd12c5c00142a9eb0c0e029f999a1e945a70110c944d5d5981c9814fb051e88c36f0c14d9acdfc3040b37fcc77fa1bfc23466730a108849e0a08f5e9c79331b04803e568ea4b553ce3f1",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364130",
+ "pk": "02defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34"
+ },
+ {
+ "beta": "4b00d6d00864c7972105755b538d5f62a3585b6e8e7061fd107317fa1004efc0",
+ "alpha": "73616d706c65",
+ "pi": "03df963611501cf382e2730131618377ab38486f483db1eab7feb6ade0e1b0141bd3d291b7e45a1b94cabbafa5fca3fb7ba36b158bbcdb2292383689a6231e201a3f78f9f40757e99f80e8032adbc8d4ce",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364131",
+ "pk": "02e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a"
+ },
+ {
+ "beta": "e1e9b8491278b6faf79d433cee7d9b01256f18b3d63601f6231332ce3751411c",
+ "alpha": "73616d706c65",
+ "pi": "03ee58341c2222f7671318eff4bf2bd5588221d37d133a8aafcff5162d56af906581ce8cc5d45d546b8cf2c6d22026b934688e9a68555d4386d75f9b9e554b58b886ad91285872a2a6f137576b6bf9513f",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364132",
+ "pk": "03d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e"
+ },
+ {
+ "beta": "72c8e10530d3f0c6e452f8f20d911908eb01887c62bbae0b1eb35cb1f36b7985",
+ "alpha": "73616d706c65",
+ "pi": "03ae19c4bac9d64009b7dabf9095c3ee3c848249269d41d5ee492683cef4a0b8464fa567b84a2bfe1c7359696522d01e083defdf2c4fe5aaad7bf67c93aab74d23069d05419c59c5cd5daed14e63bdc26f",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364133",
+ "pk": "02499fdf9e895e719cfd64e67f07d38e3226aa7b63678949e6e49b241a60e823e4"
+ },
+ {
+ "beta": "11fee8e23d484d9aa8ed151f8452be11e70cfad8a44f707c00b04a11270c3d7a",
+ "alpha": "73616d706c65",
+ "pi": "0261cb37ca1f9c0ee11e41aadf4637fdddccb3f70f8ff1903727fbc2bd220720e737048df6aa7ddec95dc6a5f93f6808b5bbf2983c1733ce7b686dddc457001dbbae277d251d61f69e1af22d69b60c975e",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364134",
+ "pk": "02f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8"
+ },
+ {
+ "beta": "dfa3543db662a08aac90bfd7dd9b39b77dacf16dda462fe5eaa26b0f595fc0f5",
+ "alpha": "73616d706c65",
+ "pi": "0376661cbff92aae582298a7348f4d8f7834e2d8f6707c9706f52e65aacf968d80b24c972d16acca689cf66a1d100c26d2b141b1c8b9835e6710db5126284b9540f43cf31394f9b3e0a87449df7ef6aee6",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364135",
+ "pk": "02d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a"
+ },
+ {
+ "beta": "caae0b8dd19e20fd52f43b2fd416228b46ad625aa68ef6424ff388fb4727e0dc",
+ "alpha": "73616d706c65",
+ "pi": "0204fa576f63771c34e6cdb98f59997584528d109c7592ab867374d9b91051a4d1e875685ea35673d901ff06f18d7e89bc098be8762abf7688dba945d09d9b71348624b40c4b903de2bd3cc44abb2fafc7",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364136",
+ "pk": "02774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb"
+ },
+ {
+ "beta": "97e0785b78305d909af2a255e1b26d4faf5879d4e7640bceac71e56b3851bec0",
+ "alpha": "73616d706c65",
+ "pi": "024d4ff3ad7689b905b5c4be9de0bd8d7960e30f145903fe715af943852229f269122fadc5f835ee029d306ad7d90f5c6011ad67d24a327cccf3f39018e34df7a1544d6748755fa07ce2013729816e2330",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364137",
+ "pk": "02a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7"
+ },
+ {
+ "beta": "e0a3519f3dd1597039b5617d5b09c8ed5c723d1589010c1d6284dd8fb9d5ea7b",
+ "alpha": "73616d706c65",
+ "pi": "022eb72eccc7228307eaf7946a28feac02de8223534800cc71d7d1195fb0a7c88630d9be168212ecee12897644c456c22eaa9be58c9c8bb92a86a73e787f44f55a57203ddd9d80bf4e1ad4ac21c03a5f2c",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364138",
+ "pk": "02acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe"
+ },
+ {
+ "beta": "ba9235a6d8c3a2efa2b6cc2d8f23d3b9169ae0a0363db2192465aefbff07ed09",
+ "alpha": "73616d706c65",
+ "pi": "038fbe2d674ae973b17ee720413e94ee0387d1f794766ec9649d97ccbf6afaa22ce90783ffc7eb0c082db401cb81203ced6223bf24f66cd2c19351f4e18c9fd7a2884d82870ea357bd5bbb4ce9e1e4e840",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364139",
+ "pk": "032f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01"
+ },
+ {
+ "beta": "9c9dc6b4b61b59950c15c35fb665cc94879b0297fac4edf2803de529b00f8c0c",
+ "alpha": "73616d706c65",
+ "pi": "0235731391a2ed6ff06cdb279b71ae0151d4f43041cfa8c27d958ab95d08b1bcae807694c56c2ec4ebc855253e3a66e798ea6701ae6861a2ad67a8c2a3ce14c3e8af2f3936fabd5a13dde062afd040e50a",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413a",
+ "pk": "035cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc"
+ },
+ {
+ "beta": "110f1fa93881cf624c22b72f1b79e6138a052a462ff10d7aa56f501835a8f6b8",
+ "alpha": "73616d706c65",
+ "pi": "03913bdfa315ab0963b03c34ebe265751e8b5904837bbda75629423b485924fee45b397e9d697239fdcfd435f1b21082d94f1917c792300c4ada68c0ac4e9da7cf2db99c5cbf2775ac4161ea2ed3c589a6",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413b",
+ "pk": "02fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556"
+ },
+ {
+ "beta": "a43ebaef2262310b95e140287c861c53edefc13c37696c3f89234d1a45eccf17",
+ "alpha": "73616d706c65",
+ "pi": "024dbc319514312b5544e6b587a978dfccbdc862d7fc33c5dda706efb569613df99fa8b04b237169cb92397564f92bd1e45e041817e7a3368fa1f47fcca1e9bd01a6915e645b2d411815b2b95c9efef590",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413c",
+ "pk": "032f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4"
+ },
+ {
+ "beta": "c8952a9439d26d3e761399de1fd734a2338c15893ece5a3efc72e25c9f007da8",
+ "alpha": "73616d706c65",
+ "pi": "03e30118c907034baf1456063bf7b423972e13e1743bf8dbb2e00fd8ba4a8c367a299bc3859123464d87fd4a508e5a1321f6bde3f00104b2c8af1769781dfb02e749946f4e17f6e429be0f4e4e3085e320",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413d",
+ "pk": "03e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13"
+ },
+ {
+ "beta": "25daded1cb7561c8e0013315a6f6d9dd1611d95c92caf5f920bc437ae0180a55",
+ "alpha": "73616d706c65",
+ "pi": "02ed1bb54a9092c8fd50ae8cea3322e127600a0e32840d9bc4664cfab08b1c6ba3a36ad7913367088f6e6cdbc91a061cfbd0fab0093344414aa16e43dcc5394c7a06cb46afb049eeffc2e99d16992bc228",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413e",
+ "pk": "03f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9"
+ },
+ {
+ "beta": "3bcee6576d82d011563480c8fcc5751ba6aea58313dbba4cb278d2f74eaee3ea",
+ "alpha": "73616d706c65",
+ "pi": "03359425334b14173856433b4e695f1d19c7c0cb4eb9b5c72b0b00afe170ce7fd738334a976a8be4582b05a480cdecf8a4f4dd9d0694ae1dcb384429a1c99082bdb2845e2c3010054071489f41fc4b65a5",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413f",
+ "pk": "03c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5"
+ },
+ {
+ "beta": "8efc7ce3fa0ee91c2e7d45ead94883776e37bdb3af67f386e7ec500e76e066dd",
+ "alpha": "73616d706c65",
+ "pi": "03cc27d840191d06dfca94d9346cc5b85830dcf9c9e7e4a41cc857d841bd48186c6c5d463591b9632297b3aab781d23263fd9cfc41fbb6affa02840bb903f51b494dc492087ba6fe04acf7c5b54ec0de24",
+ "sk": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
+ "pk": "0379be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
+ }
+]
\ No newline at end of file
diff --git a/test/AElf.Kernel.Consensus.AEDPoS.Tests/AEDPoSTestAElfModule.cs b/test/AElf.Kernel.Consensus.AEDPoS.Tests/AEDPoSTestAElfModule.cs
index 685b78a9ab..fd63a97d83 100644
--- a/test/AElf.Kernel.Consensus.AEDPoS.Tests/AEDPoSTestAElfModule.cs
+++ b/test/AElf.Kernel.Consensus.AEDPoS.Tests/AEDPoSTestAElfModule.cs
@@ -170,6 +170,17 @@ public override void ConfigureServices(ServiceConfigurationContext context)
}
}.ToByteArray())
}));
+
+ mockService.Setup(m =>
+ m.ExecuteAsync(It.IsAny(),
+ It.Is(tx =>
+ tx.MethodName == "GetRandomHash"),
+ It.IsAny()))
+ .Returns(Task.FromResult(new TransactionTrace
+ {
+ ExecutionStatus = ExecutionStatus.Executed,
+ ReturnValue = Hash.Empty.ToByteString()
+ }));
return mockService.Object;
});
diff --git a/test/AElf.Kernel.Consensus.AEDPoS.Tests/Application/AEDPoSTriggerInformationProviderTests.cs b/test/AElf.Kernel.Consensus.AEDPoS.Tests/Application/AEDPoSTriggerInformationProviderTests.cs
index e17515599c..4e4172f345 100644
--- a/test/AElf.Kernel.Consensus.AEDPoS.Tests/Application/AEDPoSTriggerInformationProviderTests.cs
+++ b/test/AElf.Kernel.Consensus.AEDPoS.Tests/Application/AEDPoSTriggerInformationProviderTests.cs
@@ -4,6 +4,7 @@
using AElf.Kernel.Consensus.AEDPoS.Application;
using AElf.Kernel.Consensus.Application;
using AElf.Standards.ACS4;
+using AElf.Types;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using Shouldly;
@@ -43,7 +44,7 @@ public Task GetTriggerInformationForBlockHeaderExtraData_ConsensusCommand_Test()
[Fact]
public async Task GetCurrentMinerList_Test()
{
- var result = await _aedpoSInformationProvider.GetCurrentMinerList(new ChainContext());
+ var result = await _aedpoSInformationProvider.GetCurrentMinerListAsync(new ChainContext());
result.Count().ShouldBe(3);
}
@@ -60,7 +61,7 @@ public void GetTriggerInformationForBlockHeaderExtraData_CommandIsNull_Test()
public void GetTriggerInformationForConsensusTransactions_CommandIsNull_Test()
{
var result =
- _triggerInformationProvider.GetTriggerInformationForConsensusTransactions(null);
+ _triggerInformationProvider.GetTriggerInformationForConsensusTransactions(new ChainContext(), null);
var triggerInformation = AElfConsensusTriggerInformation.Parser.ParseFrom(result.Value);
triggerInformation.Behaviour.ShouldBe(AElfConsensusBehaviour.UpdateValue);
}
diff --git a/test/AElf.Kernel.Consensus.Tests/ConsensusTestAElfModule.cs b/test/AElf.Kernel.Consensus.Tests/ConsensusTestAElfModule.cs
index b31b834a82..8f05ef3b78 100644
--- a/test/AElf.Kernel.Consensus.Tests/ConsensusTestAElfModule.cs
+++ b/test/AElf.Kernel.Consensus.Tests/ConsensusTestAElfModule.cs
@@ -38,7 +38,7 @@ public override void ConfigureServices(ServiceConfigurationContext context)
.Returns(new BytesValue());
mockService.Setup(m => m.GetTriggerInformationForBlockHeaderExtraData(It.IsAny()))
.Returns(new BytesValue());
- mockService.Setup(m => m.GetTriggerInformationForConsensusTransactions(It.IsAny()))
+ mockService.Setup(m => m.GetTriggerInformationForConsensusTransactions(It.IsAny(), It.IsAny()))
.Returns(new BytesValue());
return mockService.Object;
diff --git a/test/AElf.Kernel.Core.Tests/Account/Application/AccountServiceTests.cs b/test/AElf.Kernel.Core.Tests/Account/Application/AccountServiceTests.cs
index 9d9a44ed36..74bfda07dd 100644
--- a/test/AElf.Kernel.Core.Tests/Account/Application/AccountServiceTests.cs
+++ b/test/AElf.Kernel.Core.Tests/Account/Application/AccountServiceTests.cs
@@ -59,4 +59,15 @@ public async Task EncryptAndDecryptMessage_Test()
decryptMessage.ShouldBe(plainMessage);
}
+
+ [Fact]
+ public async Task Vrf_Test()
+ {
+ var alpha = "5cf8151010716e40e5349ad02821da605df22e9ac95450c7e35f04c720fd4db5";
+ var alphaBytes = Hash.LoadFromHex(alpha).ToByteArray();
+ var pi = await _accountService.ECVrfProveAsync(alphaBytes);
+ var pubkey = await _accountService.GetPublicKeyAsync();
+ var beta = CryptoHelper.ECVrfVerify(pubkey, alphaBytes, pi);
+ beta.ShouldNotBeEmpty();
+ }
}
\ No newline at end of file
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForCallThreshold.Tests/AElf.Kernel.SmartContract.ExecutionPluginForCallThreshold.Tests.csproj b/test/AElf.Kernel.SmartContract.ExecutionPluginForCallThreshold.Tests/AElf.Kernel.SmartContract.ExecutionPluginForCallThreshold.Tests.csproj
index 2577e808ad..572810cff3 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForCallThreshold.Tests/AElf.Kernel.SmartContract.ExecutionPluginForCallThreshold.Tests.csproj
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForCallThreshold.Tests/AElf.Kernel.SmartContract.ExecutionPluginForCallThreshold.Tests.csproj
@@ -47,6 +47,16 @@
Contract
PreserveNewest
+
+ false
+ Contract
+ PreserveNewest
+
+
+ false
+ Contract
+ PreserveNewest
+
@@ -72,6 +82,15 @@
Protobuf\Proto\acs5_plugin_test_contract.proto
+
+ Protobuf\Proto\parliament_contract.proto
+
+
+ Protobuf\Proto\parliament_contract_impl.proto
+
+
+ Protobuf\Proto\acs3.proto
+
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForCallThreshold.Tests/ExecutionPluginForCallThresholdTestBase.cs b/test/AElf.Kernel.SmartContract.ExecutionPluginForCallThreshold.Tests/ExecutionPluginForCallThresholdTestBase.cs
index 62a7a04a85..5dce8cc994 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForCallThreshold.Tests/ExecutionPluginForCallThresholdTestBase.cs
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForCallThreshold.Tests/ExecutionPluginForCallThresholdTestBase.cs
@@ -1,14 +1,17 @@
using System.Linq;
using System.Threading.Tasks;
using AElf.Contracts.MultiToken;
+using AElf.Contracts.Parliament;
using AElf.Contracts.TokenConverter;
using AElf.ContractTestKit;
using AElf.Cryptography.ECDSA;
using AElf.EconomicSystem;
+using AElf.Kernel.Proposal;
using AElf.Kernel.SmartContract.ExecutionPluginForCallThreshold.Tests.TestContract;
using AElf.Kernel.Token;
using AElf.Types;
using Shouldly;
+using InitializeInput = AElf.Contracts.TokenConverter.InitializeInput;
namespace AElf.Kernel.SmartContract.ExecutionPluginForCallThreshold.Tests;
@@ -39,6 +42,8 @@ public class ExecutionPluginForCallThresholdTestBase : ContractTestBase Accounts[0].KeyPair;
internal ECKeyPair OtherTester => Accounts[1].KeyPair;
@@ -51,6 +56,7 @@ public class ExecutionPluginForCallThresholdTestBase : ContractTestBase kv.Key.Contains("TestContract")).Value;
+ var code = Codes.Single(kv => kv.Key.Contains("ExecutionPluginForCallThreshold.Tests.TestContract")).Value;
TestContractAddress = await DeployContractAsync(category, code, HashHelper.ComputeFrom("TestContract"),
DefaultSenderKeyPair);
DefaultTester =
GetTester(TestContractAddress, DefaultSenderKeyPair);
}
+ // Parliament
+ {
+ var code = Codes.Single(kv => kv.Key.Contains("MockParliament")).Value;
+ ParliamentAddress = await DeploySystemSmartContract(category, code,
+ ParliamentSmartContractAddressNameProvider.Name, DefaultSenderKeyPair);
+ ParliamentContractStub =
+ GetTester(ParliamentAddress,
+ DefaultSenderKeyPair);
+ }
+ }
+
+ private async Task InitializedParliament()
+ {
+ await ParliamentContractStub.Initialize.SendAsync(new AElf.Contracts.Parliament.InitializeInput
+ {
+ ProposerAuthorityRequired = false,
+ PrivilegedProposer = DefaultSender
+ });
}
private async Task InitializeTokenAsync()
@@ -98,7 +122,8 @@ private async Task InitializeTokenAsync()
IsBurnable = true,
TokenName = "elf token",
TotalSupply = 1000_00000000L,
- Issuer = DefaultSender
+ Issuer = DefaultSender,
+ Owner = DefaultSender
});
createResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
@@ -122,7 +147,8 @@ private async Task InitializeTokenAsync()
IsBurnable = true,
TokenName = "WRITE token",
TotalSupply = 1000_0000L,
- Issuer = DefaultSender
+ Issuer = DefaultSender,
+ Owner = DefaultSender
});
createResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests.csproj b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests.csproj
index 17473c3736..8a46bd22dc 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests.csproj
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests.csproj
@@ -60,11 +60,6 @@
Contract
PreserveNewest
-
- false
- Contract
- PreserveNewest
-
false
Contract
@@ -85,6 +80,11 @@
Contract
PreserveNewest
+
+ false
+ Contract
+ PreserveNewest
+
@@ -107,6 +107,9 @@
Protobuf\Proto\token_contract.proto
+
+ Protobuf\Proto\token_contract_impl.proto
+
Protobuf\Proto\acs1_plugin_test_contract.proto
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutePluginTransactionDirectlyTest.cs b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutePluginTransactionDirectlyTest.cs
index a72b124533..49e50a0205 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutePluginTransactionDirectlyTest.cs
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutePluginTransactionDirectlyTest.cs
@@ -1,22 +1,17 @@
-using System;
using System.Collections.Generic;
using System.Linq;
-using System.Runtime.InteropServices;
using System.Threading.Tasks;
-using AElf.Standards.ACS1;
-using AElf.Standards.ACS3;
using AElf.Contracts.MultiToken;
using AElf.CSharp.Core;
-using AElf.CSharp.Core.Extension;
+using AElf.Standards.ACS1;
using AElf.Types;
-using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using Shouldly;
using Xunit;
namespace AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests;
-public class ExecutePluginTransactionDirectlyTest : ExecutePluginTransactionDirectlyForMethodFeeTestBase
+public partial class ExecutePluginTransactionDirectlyTest : ExecutePluginTransactionDirectlyForMethodFeeTestBase
{
[Fact]
public async Task ChargeTransactionFees_Invalid_Input_Test()
@@ -43,6 +38,20 @@ public async Task ChargeTransactionFees_Without_Primary_Token_Test()
// input With Primary Token
await SetPrimaryTokenSymbolAsync();
var beforeChargeBalance = await GetBalanceAsync(address, nativeTokenSymbol);
+
+ await TokenContractImplStub.SetMethodFee.SendAsync(new MethodFees
+ {
+ MethodName = methodName,
+ Fees =
+ {
+ new MethodFee
+ {
+ Symbol = NativeTokenSymbol,
+ BasicFee = 1000
+ }
+ }
+ });
+
var chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(new ChargeTransactionFeesInput
{
ContractAddress = TokenContractAddress,
@@ -79,8 +88,7 @@ public async Task Set_Repeat_Token_Test()
}
};
var sizeFee = 0;
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractImplContainer.TokenContractImplStub.SetMethodFee), methodFee);
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
var beforeChargeBalance = await GetBalanceAsync(address, NativeTokenSymbol);
var chargeTransactionFeesInput = new ChargeTransactionFeesInput
{
@@ -129,8 +137,7 @@ public async Task ChargeTransactionFees_With_Different_Transaction_Size_Fee_Toke
}
}
};
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractImplContainer.TokenContractImplStub.SetMethodFee), methodFee);
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
var tokenSymbolList = new[] { NativeTokenSymbol, "CWJ", "YPA" };
var tokenCount = 3;
var orderedSymbolList = new string[tokenCount];
@@ -156,8 +163,7 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
});
}
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractImplContainer.TokenContractImplStub.SetSymbolsToPayTxSizeFee), sizeFeeSymbolList);
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
var beforeBalanceList = await GetDefaultBalancesAsync(orderedSymbolList);
var chargeTransactionFeesInput = new ChargeTransactionFeesInput
@@ -214,15 +220,15 @@ public async Task DonateResourceToken_Test(long[] initialBalances, long[] tokenF
if (!isMainChain)
{
var defaultParliament = await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractContainer.TokenContractStub.InitializeFromParentChain),
- new InitializeFromParentChainInput
- {
- Creator = defaultParliament
- });
+ await TokenContractStub.InitializeFromParentChain.SendAsync(new InitializeFromParentChainInput
+ {
+ Creator = defaultParliament
+ });
}
- await TokenContractStub.DonateResourceToken.SendAsync(feeMap);
+ var result = await TokenContractStub.DonateResourceToken.SendAsync(feeMap);
+ var transactionFeeClaimedDic = result.TransactionResult.Logs.Where(o => o.Name == nameof(ResourceTokenClaimed))
+ .Select(o => ResourceTokenClaimed.Parser.ParseFrom(o.NonIndexed)).ToDictionary(o => o.Symbol, o => o);
for (var i = 0; i < symbolList.Length; i++)
{
@@ -233,6 +239,12 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
var consensusBalance = await GetBalanceAsync(ConsensusContractAddress, symbolList[i]);
consensusBalance.ShouldBe(initialBalances[i] - lastBalances[i]);
}
+
+ var transactionFeeClaimed = transactionFeeClaimedDic[symbolList[i]];
+ transactionFeeClaimed.Symbol.ShouldBe(symbolList[i]);
+ transactionFeeClaimed.Amount.ShouldBe(tokenFee[i] > initialBalances[i] ? initialBalances[i] : tokenFee[i]);
+ transactionFeeClaimed.Payer.ShouldBe(DefaultSender);
+ transactionFeeClaimed.Receiver.ShouldBe(ConsensusContractAddress);
}
}
@@ -250,7 +262,14 @@ public async Task ClaimTransactionFee_Balance_WithOut_Receiver_Test()
{ tokenSymbol, feeAmount }
}
};
- await TokenContractStub.ClaimTransactionFees.SendAsync(claimFeeInput);
+ var result = await TokenContractStub.ClaimTransactionFees.SendAsync(claimFeeInput);
+
+ var transactionFeeClaimed = TransactionFeeClaimed.Parser.ParseFrom(result.TransactionResult.Logs
+ .First(l => l.Name.Contains(nameof(TransactionFeeClaimed))).NonIndexed);
+ transactionFeeClaimed.Symbol.ShouldBe(tokenSymbol);
+ transactionFeeClaimed.Amount.ShouldBe(feeAmount);
+ transactionFeeClaimed.Receiver.ShouldBe(TokenContractAddress);
+
var afterBurned = await GetTokenSupplyAmount(tokenSymbol);
(beforeBurned - afterBurned).ShouldBe(feeAmount);
}
@@ -266,10 +285,8 @@ public async Task ClaimTransactionFee_Balance_With_Receiver_Test()
{
Creator = receiver
};
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractImplContainer.TokenContractImplStub.InitializeFromParentChain), input);
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractImplContainer.TokenContractImplStub.SetFeeReceiver), receiver);
+ await TokenContractImplStub.InitializeFromParentChain.SendAsync(input);
+ await TokenContractImplStub.SetFeeReceiver.SendAsync(receiver);
var beforeBurned = await GetTokenSupplyAmount(tokenSymbol);
var beforeBalance = await GetBalanceAsync(receiver, tokenSymbol);
var claimFeeInput = new TotalTransactionFeesMap
@@ -279,7 +296,14 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
{ tokenSymbol, feeAmount }
}
};
- await TokenContractStub.ClaimTransactionFees.SendAsync(claimFeeInput);
+ var result = await TokenContractStub.ClaimTransactionFees.SendAsync(claimFeeInput);
+
+ var transactionFeeClaimed = TransactionFeeClaimed.Parser.ParseFrom(result.TransactionResult.Logs
+ .First(l => l.Name.Contains(nameof(TransactionFeeClaimed))).NonIndexed);
+ transactionFeeClaimed.Symbol.ShouldBe(tokenSymbol);
+ transactionFeeClaimed.Amount.ShouldBe(feeAmount);
+ transactionFeeClaimed.Receiver.ShouldBe(TokenContractAddress);
+
var afterBurned = await GetTokenSupplyAmount(tokenSymbol);
var afterBalance = await GetBalanceAsync(receiver, tokenSymbol);
var shouldBurned = feeAmount.Div(10);
@@ -301,22 +325,29 @@ public async Task FreeAllowancesTest(long threshold, long initialBalance, long f
await SetPrimaryTokenSymbolAsync();
await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialBalance);
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractStub.ConfigMethodFeeFreeAllowances), new MethodFeeFreeAllowancesConfig
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
{
- FreeAllowances = new MethodFeeFreeAllowances
+ Value =
{
- Value =
+ new ConfigTransactionFeeFreeAllowance
{
- new MethodFeeFreeAllowance
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
{
- Symbol = NativeTokenSymbol,
- Amount = freeAmount
- }
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = freeAmount
+ }
+ }
+ },
+ RefreshSeconds = refreshSeconds,
+ Threshold = threshold
}
- },
- RefreshSeconds = refreshSeconds,
- Threshold = threshold
+ }
});
var methodFee = new MethodFees
@@ -331,19 +362,20 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
}
}
};
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractImplContainer.TokenContractImplStub.SetMethodFee), methodFee);
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
{
- var freeAllowances = await TokenContractStub.GetMethodFeeFreeAllowances.CallAsync(DefaultSender);
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
if (threshold <= initialBalance)
{
- freeAllowances.Value.First().Symbol.ShouldBe(NativeTokenSymbol);
- freeAllowances.Value.First().Amount.ShouldBe(freeAmount);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(freeAmount);
}
else
{
- freeAllowances.Value.ShouldBeEmpty();
+ freeAllowances.Map.ShouldBeEmpty();
}
}
@@ -359,8 +391,7 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
}
}
};
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractImplContainer.TokenContractImplStub.SetSymbolsToPayTxSizeFee), sizeFeeSymbolList);
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
var chargeTransactionFeesInput = new ChargeTransactionFeesInput
{
@@ -377,26 +408,21 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
chargeFeeRet.Output.Success.ShouldBe(true);
{
- var freeAllowances = await TokenContractStub.GetMethodFeeFreeAllowances.CallAsync(DefaultSender);
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
if (threshold <= initialBalance)
{
- freeAllowances.Value.First().Symbol.ShouldBe(NativeTokenSymbol);
- freeAllowances.Value.First().Amount.ShouldBe(newFreeAllowance);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(newFreeAllowance);
}
else
{
- freeAllowances.Value.ShouldBeEmpty();
+ freeAllowances.Map.ShouldBeEmpty();
}
}
- {
- var balance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
- {
- Symbol = NativeTokenSymbol,
- Owner = DefaultSender
- });
- balance.Balance.ShouldBe(afterBalance);
- }
+ await CheckDefaultSenderTokenAsync(NativeTokenSymbol, afterBalance);
}
[Theory]
@@ -425,27 +451,34 @@ public async Task FreeAllowances_MultToken_Test(
await IssueTokenToDefaultSenderAsync(sizeFeeSymbol, sizeFeeBalance);
}
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractStub.ConfigMethodFeeFreeAllowances), new MethodFeeFreeAllowancesConfig
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
{
- FreeAllowances = new MethodFeeFreeAllowances
+ Value =
{
- Value =
+ new ConfigTransactionFeeFreeAllowance
{
- new MethodFeeFreeAllowance
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
{
- Symbol = basicFeeSymbol,
- Amount = baseFeeFreeAmount
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = basicFeeSymbol,
+ Amount = baseFeeFreeAmount
+ },
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = sizeFeeSymbol,
+ Amount = sizeFeeFreeAmount
+ }
+ }
},
- new MethodFeeFreeAllowance
- {
- Symbol = sizeFeeSymbol,
- Amount = sizeFeeFreeAmount
- }
+ RefreshSeconds = 100,
+ Threshold = threshold,
+ Symbol = NativeTokenSymbol
}
- },
- RefreshSeconds = 100,
- Threshold = threshold
+ }
});
@@ -461,8 +494,7 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
}
}
};
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractImplContainer.TokenContractImplStub.SetMethodFee), methodFee);
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
var sizeFeeSymbolList = new SymbolListToPayTxSizeFee
{
@@ -482,21 +514,23 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
}
}
};
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractImplContainer.TokenContractImplStub.SetSymbolsToPayTxSizeFee), sizeFeeSymbolList);
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
{
- var freeAllowances = await TokenContractStub.GetMethodFeeFreeAllowances.CallAsync(DefaultSender);
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
if (threshold <= initialBalance)
{
- freeAllowances.Value.First().Symbol.ShouldBe(basicFeeSymbol);
- freeAllowances.Value.First().Amount.ShouldBe(baseFeeFreeAmount);
- freeAllowances.Value.Last().Symbol.ShouldBe(sizeFeeSymbol);
- freeAllowances.Value.Last().Amount.ShouldBe(sizeFeeFreeAmount);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(basicFeeSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(basicFeeSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(baseFeeFreeAmount);
+ freeAllowances.Map.Values.First().Map.Keys.Last().ShouldBe(sizeFeeSymbol);
+ freeAllowances.Map.Values.First().Map.Values.Last().Symbol.ShouldBe(sizeFeeSymbol);
+ freeAllowances.Map.Values.First().Map.Values.Last().Amount.ShouldBe(sizeFeeFreeAmount);
}
else
{
- freeAllowances.Value.ShouldBeEmpty();
+ freeAllowances.Map.ShouldBeEmpty();
}
}
@@ -512,33 +546,25 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
chargeFeeRet.Output.Success.ShouldBe(true);
{
- var freeAllowances = await TokenContractStub.GetMethodFeeFreeAllowances.CallAsync(DefaultSender);
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
if (threshold <= initialBalance)
{
- freeAllowances.Value.First().Symbol.ShouldBe(basicFeeSymbol);
- freeAllowances.Value.First().Amount.ShouldBe(newBaseFreeAllowance);
- freeAllowances.Value.Last().Symbol.ShouldBe(sizeFeeSymbol);
- freeAllowances.Value.Last().Amount.ShouldBe(newSizeFreeAllowance);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(basicFeeSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(basicFeeSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(newBaseFreeAllowance);
+ freeAllowances.Map.Values.First().Map.Keys.Last().ShouldBe(sizeFeeSymbol);
+ freeAllowances.Map.Values.First().Map.Values.Last().Symbol.ShouldBe(sizeFeeSymbol);
+ freeAllowances.Map.Values.First().Map.Values.Last().Amount.ShouldBe(newSizeFreeAllowance);
}
else
{
- freeAllowances.Value.ShouldBeEmpty();
+ freeAllowances.Map.ShouldBeEmpty();
}
}
- var baseFeeSymbolBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
- {
- Symbol = basicFeeSymbol,
- Owner = DefaultSender
- });
- baseFeeSymbolBalance.Balance.ShouldBe(afterBaseFeeBalance);
-
- var sizeFeeSymbolBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
- {
- Symbol = sizeFeeSymbol,
- Owner = DefaultSender
- });
- sizeFeeSymbolBalance.Balance.ShouldBe(afterSizeFeeBalance);
+ await CheckDefaultSenderTokenAsync(basicFeeSymbol, afterBaseFeeBalance);
+ await CheckDefaultSenderTokenAsync(sizeFeeSymbol, afterSizeFeeBalance);
}
[Theory]
@@ -559,7 +585,7 @@ public async Task ChargeTransactionFee_Delegate(
await CreateTokenAsync(DefaultSender, sizeFeeSymbol);
await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialBalance);
- await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegateeBalance, delegateeAddress);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegateeBalance, DelegateeAddress);
await IssueTokenToUserAsync(NativeTokenSymbol, initialUserBalance, userAddress);
var delegations = new Dictionary
@@ -568,20 +594,21 @@ public async Task ChargeTransactionFee_Delegate(
[basicFeeSymbol] = delegateeAmountBasic,
[sizeFeeSymbol] = delegateeAmountSize
};
- var transactionResult = await TokenContractStub2.SetTransactionFeeDelegations.SendAsync(new SetTransactionFeeDelegationsInput
- {
- DelegatorAddress = DefaultSender,
- Delegations =
+ var transactionResult = await TokenContractStub2.SetTransactionFeeDelegations.SendAsync(
+ new SetTransactionFeeDelegationsInput
{
- delegations
- }
- });
+ DelegatorAddress = DefaultSender,
+ Delegations =
+ {
+ delegations
+ }
+ });
// Test Case 11
{
var result = await TokenContractStubA.GetTransactionFeeDelegationsOfADelegatee.CallAsync(
new GetTransactionFeeDelegationsOfADelegateeInput
{
- DelegateeAddress = delegateeAddress,
+ DelegateeAddress = DelegateeAddress,
DelegatorAddress = DefaultSender
});
result.BlockHeight.ShouldBe(transactionResult.TransactionResult.BlockNumber);
@@ -590,7 +617,7 @@ public async Task ChargeTransactionFee_Delegate(
var result = await TokenContractStub.GetTransactionFeeDelegationsOfADelegatee.CallAsync(
new GetTransactionFeeDelegationsOfADelegateeInput
{
- DelegateeAddress = delegateeAddress,
+ DelegateeAddress = DelegateeAddress,
DelegatorAddress = DefaultSender
});
result.Delegations[NativeTokenSymbol].ShouldBe(delegateeAmountNativeToken);
@@ -602,46 +629,57 @@ public async Task ChargeTransactionFee_Delegate(
{
await IssueTokenToDefaultSenderAsync(basicFeeSymbol, baseFeeBalance);
await IssueTokenToDefaultSenderAsync(sizeFeeSymbol, sizeFeeBalance);
- await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegateBalance, delegateeAddress);
- await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegateBalance, delegateeAddress);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegateBalance, DelegateeAddress);
await IssueTokenToUserAsync(basicFeeSymbol, baseFeeUserBalance, userAddress);
await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeUserBalance, userAddress);
}
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractStub.ConfigMethodFeeFreeAllowances), new MethodFeeFreeAllowancesConfig
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
{
- FreeAllowances = new MethodFeeFreeAllowances
+ Value =
{
- Value =
+ new ConfigTransactionFeeFreeAllowance
{
- new MethodFeeFreeAllowance
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
{
- Symbol = basicFeeSymbol,
- Amount = baseFeeFreeAmount
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = basicFeeSymbol,
+ Amount = baseFeeFreeAmount
+ },
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = sizeFeeSymbol,
+ Amount = sizeFeeFreeAmount
+ }
+ }
},
- new MethodFeeFreeAllowance
- {
- Symbol = sizeFeeSymbol,
- Amount = sizeFeeFreeAmount
- }
+ Symbol = NativeTokenSymbol,
+ RefreshSeconds = 100,
+ Threshold = threshold
}
- },
- RefreshSeconds = 100,
- Threshold = threshold
+ }
});
+
{
- var freeAllowances = await TokenContractStub.GetMethodFeeFreeAllowances.CallAsync(userAddress);
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(userAddress);
if (threshold <= initialBalance)
{
- freeAllowances.Value.First().Symbol.ShouldBe(basicFeeSymbol);
- freeAllowances.Value.First().Amount.ShouldBe(baseFeeFreeAmount);
- freeAllowances.Value.Last().Symbol.ShouldBe(sizeFeeSymbol);
- freeAllowances.Value.Last().Amount.ShouldBe(sizeFeeFreeAmount);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(basicFeeSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(basicFeeSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(baseFeeFreeAmount);
+ freeAllowances.Map.Values.First().Map.Keys.Last().ShouldBe(sizeFeeSymbol);
+ freeAllowances.Map.Values.First().Map.Values.Last().Symbol.ShouldBe(sizeFeeSymbol);
+ freeAllowances.Map.Values.First().Map.Values.Last().Amount.ShouldBe(sizeFeeFreeAmount);
}
else
{
- freeAllowances.Value.ShouldBeEmpty();
+ freeAllowances.Map.ShouldBeEmpty();
}
}
@@ -657,8 +695,8 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
}
}
};
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractImplContainer.TokenContractImplStub.SetMethodFee), methodFee);
+
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
var sizeFeeSymbolList = new SymbolListToPayTxSizeFee
{
@@ -678,9 +716,8 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
}
}
};
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractImplContainer.TokenContractImplStub.SetSymbolsToPayTxSizeFee), sizeFeeSymbolList);
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
var chargeTransactionFeesInput = new ChargeTransactionFeesInput
{
@@ -706,7 +743,7 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
var delegationResult = await TokenContractStub.GetTransactionFeeDelegationsOfADelegatee.CallAsync(
new GetTransactionFeeDelegationsOfADelegateeInput
{
- DelegateeAddress = delegateeAddress,
+ DelegateeAddress = DelegateeAddress,
DelegatorAddress = DefaultSender
});
var chargeFeeRetDefault =
@@ -714,7 +751,7 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
if (chargeFeeRetDefault.Transaction.RefBlockNumber >= delegationResult.BlockHeight + 2)
{
chargeFeeRetDefault.Output.Success.ShouldBe(true);
-
+
var afterBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
Symbol = basicFeeSymbol,
@@ -725,13 +762,13 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
var afterDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
Symbol = basicFeeSymbol,
- Owner = delegateeAddress
+ Owner = DelegateeAddress
});
afterDelegateeBalance.Balance.ShouldBe(afterBalanceDelegatee);
var delegation = await TokenContractStub.GetTransactionFeeDelegationsOfADelegatee.CallAsync(
new GetTransactionFeeDelegationsOfADelegateeInput
{
- DelegateeAddress = delegateeAddress,
+ DelegateeAddress = DelegateeAddress,
DelegatorAddress = DefaultSender
});
delegation.Delegations[basicFeeSymbol].ShouldBe(afterDelegateeAmount);
@@ -739,11 +776,11 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
else
{
chargeFeeRetDefault.Output.Success.ShouldBe(false);
-
+
var delegation = await TokenContractStub.GetTransactionFeeDelegationsOfADelegatee.CallAsync(
new GetTransactionFeeDelegationsOfADelegateeInput
{
- DelegateeAddress = delegateeAddress,
+ DelegateeAddress = DelegateeAddress,
DelegatorAddress = DefaultSender
});
delegation.Delegations[basicFeeSymbol].ShouldBe(delegateeAmountBasic);
@@ -771,7 +808,7 @@ public async Task ChargeTransactionFee_Delegate_Failed(
await CreateTokenAsync(DefaultSender, sizeFeeSymbol);
await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialBalance);
- await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegateeBalance, delegateeAddress);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegateeBalance, DelegateeAddress);
var delegations = new Dictionary
{
@@ -791,7 +828,7 @@ await TokenContractStub2.SetTransactionFeeDelegations.SendAsync(new SetTransacti
var result = await TokenContractStub.GetTransactionFeeDelegationsOfADelegatee.CallAsync(
new GetTransactionFeeDelegationsOfADelegateeInput
{
- DelegateeAddress = delegateeAddress,
+ DelegateeAddress = DelegateeAddress,
DelegatorAddress = DefaultSender
});
result.Delegations[NativeTokenSymbol].ShouldBe(delegateeAmountNativeToken);
@@ -802,31 +839,38 @@ await TokenContractStub2.SetTransactionFeeDelegations.SendAsync(new SetTransacti
{
await IssueTokenToDefaultSenderAsync(basicFeeSymbol, baseFeeBalance);
await IssueTokenToDefaultSenderAsync(sizeFeeSymbol, sizeFeeBalance);
- await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegateBalance, delegateeAddress);
- await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegateBalance, delegateeAddress);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegateBalance, DelegateeAddress);
}
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractStub.ConfigMethodFeeFreeAllowances), new MethodFeeFreeAllowancesConfig
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
{
- FreeAllowances = new MethodFeeFreeAllowances
+ Value =
{
- Value =
+ new ConfigTransactionFeeFreeAllowance
{
- new MethodFeeFreeAllowance
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
{
- Symbol = basicFeeSymbol,
- Amount = baseFeeFreeAmount
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = basicFeeSymbol,
+ Amount = baseFeeFreeAmount
+ },
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = sizeFeeSymbol,
+ Amount = sizeFeeFreeAmount
+ }
+ }
},
- new MethodFeeFreeAllowance
- {
- Symbol = sizeFeeSymbol,
- Amount = sizeFeeFreeAmount
- }
+ RefreshSeconds = 100,
+ Threshold = threshold,
+ Symbol = NativeTokenSymbol
}
- },
- RefreshSeconds = 100,
- Threshold = threshold
+ }
});
var methodFee = new MethodFees
@@ -841,8 +885,7 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
}
}
};
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractImplContainer.TokenContractImplStub.SetMethodFee), methodFee);
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
var sizeFeeSymbolList = new SymbolListToPayTxSizeFee
{
@@ -862,8 +905,7 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
}
}
};
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractImplContainer.TokenContractImplStub.SetSymbolsToPayTxSizeFee), sizeFeeSymbolList);
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
var chargeTransactionFeesInput = new ChargeTransactionFeesInput
@@ -890,13 +932,13 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
var afterDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
Symbol = basicFeeSymbol,
- Owner = delegateeAddress
+ Owner = DelegateeAddress
});
afterDelegateeBalance.Balance.ShouldBe(afterBalanceDelegatee);
var delegation = await TokenContractStub.GetTransactionFeeDelegationsOfADelegatee.CallAsync(
new GetTransactionFeeDelegationsOfADelegateeInput
{
- DelegateeAddress = delegateeAddress,
+ DelegateeAddress = DelegateeAddress,
DelegatorAddress = DefaultSender
});
delegation.Delegations[sizeFeeSymbol].ShouldBe(afterDelegateeAmount);
@@ -913,8 +955,8 @@ public async Task ChargeTransactionFee_Delegate_DefaultSizeFee(
await SetPrimaryTokenSymbolAsync();
await CreateTokenAsync(DefaultSender, basicFeeSymbol);
- await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegateeBalance, delegateeAddress);
- await IssueTokenToUserAsync(basicFeeSymbol, initialDelegateeBalance, delegateeAddress);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegateeBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(basicFeeSymbol, initialDelegateeBalance, DelegateeAddress);
var delegations = new Dictionary
{
@@ -933,7 +975,7 @@ await TokenContractStub2.SetTransactionFeeDelegations.SendAsync(new SetTransacti
var result = await TokenContractStub.GetTransactionFeeDelegationsOfADelegatee.CallAsync(
new GetTransactionFeeDelegationsOfADelegateeInput
{
- DelegateeAddress = delegateeAddress,
+ DelegateeAddress = DelegateeAddress,
DelegatorAddress = userAddress
});
result.Delegations[basicFeeSymbol].ShouldBe(delegateeAmountBasic);
@@ -951,8 +993,7 @@ await TokenContractStub2.SetTransactionFeeDelegations.SendAsync(new SetTransacti
}
}
};
- await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
- nameof(TokenContractImplContainer.TokenContractImplStub.SetMethodFee), methodFee);
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
var chargeTransactionFeesInput = new ChargeTransactionFeesInput
{
@@ -975,89 +1016,1570 @@ await SubmitAndPassProposalOfDefaultParliamentAsync(TokenContractAddress,
var afterDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
Symbol = basicFeeSymbol,
- Owner = delegateeAddress
+ Owner = DelegateeAddress
});
afterDelegateeBalance.Balance.ShouldBe(exceptDelegateeBalance);
var afterDelegateeElfBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
Symbol = NativeTokenSymbol,
- Owner = delegateeAddress
+ Owner = DelegateeAddress
});
afterDelegateeElfBalance.Balance.ShouldBe(exceptDelegateeElfBalance);
}
}
- private async Task GetTokenSupplyAmount(string tokenSymbol)
+ [Theory]
+ [InlineData(1000, 1000, 1000, 1000, 1000, 1000, 1000, 50, 50, 100, 100, 50, 50, 10, 10, 80, 80, 50, 30, 920)]
+ public async Task ChargeTransactionFee_DelegateNew_First(
+ long threshold, long initialBalance, long initialDelegateeBalance, long initialUserBalance,
+ long delegateeAmountNativeToken, long delegateeAmountBasic, long delegateeAmountSize,
+ long baseFeeBalance, long sizeFeeBalance, long baseFeeDelegateBalance, long sizeFeeDelegateBalance,
+ long baseFeeUserBalance, long sizeFeeUserBalance, long baseFeeFreeAmount, long sizeFeeFreeAmount,
+ long basicFee, long sizeFee, long afterBalanceDefault, long afterBalanceDelegatee, long afterDelegateeAmount
+ )
{
- var tokenInfo = await TokenContractStub.GetTokenInfo.CallAsync(new GetTokenInfoInput
+ var basicFeeSymbol = "BASIC";
+ var sizeFeeSymbol = "SIZE";
+
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAsync(DefaultSender, basicFeeSymbol);
+ await CreateTokenAsync(DefaultSender, sizeFeeSymbol);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialBalance);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegateeBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialUserBalance, userAddress);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialUserBalance, UserTomSender);
+ if (baseFeeBalance != 0 && sizeFeeBalance != 0 &&
+ baseFeeDelegateBalance != 0 && sizeFeeDelegateBalance != 0 &&
+ baseFeeUserBalance != 0 && sizeFeeUserBalance != 0)
{
- Symbol = tokenSymbol
- });
- return tokenInfo.Supply;
- }
+ await IssueTokenToDefaultSenderAsync(basicFeeSymbol, baseFeeBalance);
+ await IssueTokenToDefaultSenderAsync(sizeFeeSymbol, sizeFeeBalance);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeUserBalance, userAddress);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeUserBalance, userAddress);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeUserBalance, UserTomSender);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeUserBalance, UserTomSender);
+ }
- private async Task> GetDefaultBalancesAsync(string[] tokenSymbolList)
- {
- var balances = new List();
- foreach (var symbol in tokenSymbolList)
- balances.Add(await GetBalanceAsync(DefaultSender, symbol));
- return balances;
- }
+ var delegations = new Dictionary
+ {
+ [NativeTokenSymbol] = delegateeAmountNativeToken,
+ [basicFeeSymbol] = delegateeAmountBasic,
+ [sizeFeeSymbol] = delegateeAmountSize
+ };
+ var delegations1 = new Dictionary
+ {
+ [NativeTokenSymbol] = 5,
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ Delegations = { delegations },
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ };
+ var delegateInfo2 = new DelegateInfo
+ {
+ Delegations = { delegations },
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.TransferFrom),
+ ContractAddress = TokenContractAddress,
+ };
+ var delegateInfo3 = new DelegateInfo
+ {
+ Delegations = { delegations },
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.TransferFrom),
+ ContractAddress = ConsensusContractAddress,
+ };
+ var delegateInfo4 = new DelegateInfo
+ {
+ Delegations = { delegations1 },
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ };
+ var transactionResult = await TokenContractStubDelegate1.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DefaultSender,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ //delegate User transferFrom method
+ var transactionResult1 = await TokenContractStubDelegate1.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = userAddress,
+ DelegateInfoList = { delegateInfo2 }
+ });
+ //delegate User ConsensusContract
+ var transactionResult2 = await TokenContractStubDelegate1.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = userAddress,
+ DelegateInfoList = { delegateInfo3 }
+ });
+ var transactionResult3 = await TokenContractStubDelegate1.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = UserTomSender,
+ DelegateInfoList = { delegateInfo4 }
+ });
+ {
+ var result = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = DefaultSender,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ result.BlockHeight.ShouldBe(transactionResult.TransactionResult.BlockNumber);
+ result.Delegations[NativeTokenSymbol].ShouldBe(delegateeAmountNativeToken);
+ }
+
+ var delegationsBefore = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = userAddress,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.TransferFrom)
+ });
+ delegationsBefore.BlockHeight.ShouldBe(transactionResult1.TransactionResult.BlockNumber);
+ delegationsBefore.Delegations[NativeTokenSymbol].ShouldBe(delegateeAmountNativeToken);
+
+
+ var delegationBefore2 = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = userAddress,
+ ContractAddress = ConsensusContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.TransferFrom)
+ });
+ delegationBefore2.BlockHeight.ShouldBe(transactionResult2.TransactionResult.BlockNumber);
+ delegationBefore2.Delegations[NativeTokenSymbol].ShouldBe(delegateeAmountNativeToken);
- private async Task CreateTokenAsync(Address creator, string tokenSymbol, bool isBurned = true)
- {
- await TokenContractStub.Create.SendAsync(new CreateInput
{
- Symbol = tokenSymbol,
- TokenName = tokenSymbol + " name",
- TotalSupply = 1000_00000000,
- IsBurnable = isBurned,
- Issuer = creator,
- });
- }
+ var result = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = UserTomSender,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ result.BlockHeight.ShouldBe(transactionResult3.TransactionResult.BlockNumber);
+ result.Delegations[NativeTokenSymbol].ShouldBe(5);
+ }
- private async Task IssueTokenToDefaultSenderAsync(string tokenSymbol, long amount)
- {
- var issueResult = await TokenContractStub.Issue.SendAsync(new IssueInput()
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ RefreshSeconds = 100,
+ Threshold = threshold,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = basicFeeSymbol,
+ Amount = baseFeeFreeAmount
+ },
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = sizeFeeSymbol,
+ Amount = sizeFeeFreeAmount
+ }
+ }
+ }
+ }
+ }
+ });
{
- Symbol = tokenSymbol,
- Amount = amount,
- To = DefaultSender,
- });
- issueResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
- }
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(userAddress);
+ if (threshold <= initialBalance)
+ {
+ freeAllowances.Map.First().Value.Map.Values.First().Symbol.ShouldBe(basicFeeSymbol);
+ freeAllowances.Map.First().Value.Map.Values.First().Amount.ShouldBe(baseFeeFreeAmount);
+ freeAllowances.Map.First().Value.Map.Values.Last().Symbol.ShouldBe(sizeFeeSymbol);
+ freeAllowances.Map.First().Value.Map.Values.Last().Amount.ShouldBe(sizeFeeFreeAmount);
+ }
+ else
+ {
+ freeAllowances.Map.ShouldBeEmpty();
+ }
+ }
+ var sizeFeeSymbolList = await SetMethodOrSizeFeeAsync(basicFeeSymbol, sizeFeeSymbol, 80);
- private async Task IssueTokenToUserAsync(string tokenSymbol, long amount, Address to)
- {
- var issueResult = await TokenContractStub.Issue.SendAsync(new IssueInput()
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
{
- Symbol = tokenSymbol,
- Amount = amount,
- To = to,
- });
- issueResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
- }
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = sizeFee,
+ };
- // single node
- private async Task SubmitAndPassProposalOfDefaultParliamentAsync(Address contractAddress, string methodName,
- IMessage input)
- {
- var defaultParliament = await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
- var proposal = new CreateProposalInput
- {
- OrganizationAddress = defaultParliament,
- ToAddress = contractAddress,
- Params = input.ToByteString(),
- ContractMethodName = methodName,
- ExpiredTime = TimestampHelper.GetUtcNow().AddHours(1)
- };
- var createProposalRet = await ParliamentContractStub.CreateProposal.SendAsync(proposal);
- createProposalRet.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
- var proposalId = createProposalRet.Output;
- await ParliamentContractStub.Approve.SendAsync(proposalId);
- var releaseRet = await ParliamentContractStub.Release.SendAsync(proposalId);
- releaseRet.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+ {
+ var chargeFeeRetUser = await TokenContractStubA.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRetUser.Output.Success.ShouldBe(false);
+ chargeFeeRetUser.Output.ChargingInformation.ShouldBe("Transaction fee not enough.");
+
+ var afterBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = userAddress
+ });
+ afterBalance.Balance.ShouldBe(0);
+ }
+ {
+ var chargeFeeRetUser =
+ await TokenContractStubDelegator.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRetUser.Output.Success.ShouldBe(false);
+ chargeFeeRetUser.Output.ChargingInformation.ShouldBe("Transaction fee not enough.");
+
+ var afterBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = UserTomSender
+ });
+ afterBalance.Balance.ShouldBe(0);
+ }
+ var delegationsAfter = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = userAddress,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.TransferFrom)
+ });
+ delegationsAfter.BlockHeight.ShouldBe(transactionResult1.TransactionResult.BlockNumber);
+ delegationsAfter.Delegations[NativeTokenSymbol].ShouldBe(delegateeAmountNativeToken);
+
+
+ var delegationAfter2 = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = DefaultSender,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ delegationAfter2.BlockHeight.ShouldBe(transactionResult.TransactionResult.BlockNumber);
+ delegationAfter2.Delegations[NativeTokenSymbol].ShouldBe(delegateeAmountNativeToken);
+ {
+ var delegationResult =
+ await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = DefaultSender,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ var chargeFeeRetDefault =
+ await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ if (chargeFeeRetDefault.Transaction.RefBlockNumber >= delegationResult.BlockHeight + 2)
+ {
+ chargeFeeRetDefault.Output.Success.ShouldBe(true);
+
+ var afterBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = DefaultSender
+ });
+ afterBalance.Balance.ShouldBe(afterBalanceDefault);
+
+ var afterDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = DelegateeAddress
+ });
+ afterDelegateeBalance.Balance.ShouldBe(afterBalanceDelegatee);
+ var delegation = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = DefaultSender,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ delegation.Delegations[basicFeeSymbol].ShouldBe(afterDelegateeAmount);
+ }
+ else
+ {
+ chargeFeeRetDefault.Output.Success.ShouldBe(false);
+
+ var delegation = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = DefaultSender,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ delegation.Delegations[basicFeeSymbol].ShouldBe(delegateeAmountBasic);
+ }
+ }
+ }
+
+ [Theory]
+ [InlineData(10, 20, 100, 1000, 1000, 1000, 10, 10, 20, 20, 100, 100, 80, 80, 20, 920)]
+ public async Task ChargeTransactionFee_DelegationNew_Second_Success(
+ long initialBalance, long initialDelegateeBalance, long initialDelegatee2Balance,
+ long delegateeAmountNativeToken, long delegateeAmountBasic, long delegateeAmountSize,
+ long baseFeeBalance, long sizeFeeBalance, long baseFeeDelegateBalance, long sizeFeeDelegateBalance,
+ long baseFeeDelegate2Balance, long sizeFeeDelegate2Balance,
+ long basicFee, long sizeFee, long afterBalanceDelegatee, long afterDelegateeAmount)
+ {
+ var basicFeeSymbol = "BASIC";
+ var sizeFeeSymbol = "SIZE";
+
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAsync(DefaultSender, basicFeeSymbol);
+ await CreateTokenAsync(DefaultSender, sizeFeeSymbol);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialBalance);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegateeBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegatee2Balance, Delegatee2Address);
+ if (baseFeeBalance != 0 && sizeFeeBalance != 0 &&
+ baseFeeDelegateBalance != 0 && sizeFeeDelegateBalance != 0 &&
+ baseFeeDelegate2Balance != 0 && sizeFeeDelegate2Balance != 0)
+ {
+ await IssueTokenToDefaultSenderAsync(basicFeeSymbol, baseFeeBalance);
+ await IssueTokenToDefaultSenderAsync(sizeFeeSymbol, sizeFeeBalance);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegate2Balance, Delegatee2Address);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegate2Balance, Delegatee2Address);
+ }
+
+ var delegations = new Dictionary
+ {
+ [NativeTokenSymbol] = 5,
+ };
+ var delegations2 = new Dictionary
+ {
+ [NativeTokenSymbol] = delegateeAmountNativeToken,
+ [basicFeeSymbol] = delegateeAmountBasic,
+ [sizeFeeSymbol] = delegateeAmountSize
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ Delegations = { delegations },
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ };
+ var delegateInfo2 = new DelegateInfo
+ {
+ Delegations = { delegations2 },
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ };
+ await TokenContractStubDelegate1.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DefaultSender,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ await TokenContractStubDelegate2.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DelegateeAddress,
+ DelegateInfoList = { delegateInfo2 }
+ });
+
+ var sizeFeeSymbolList = await SetMethodOrSizeFeeAsync(basicFeeSymbol, sizeFeeSymbol, 80);
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = sizeFee,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+ var delegationResult =
+ await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = DefaultSender,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ var delegationResult2 =
+ await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = Delegatee2Address,
+ DelegatorAddress = DelegateeAddress,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ var chargeFeeRetDefault = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ if (chargeFeeRetDefault.Transaction.RefBlockNumber >= delegationResult.BlockHeight + 2 &&
+ chargeFeeRetDefault.Transaction.RefBlockNumber >= delegationResult2.BlockHeight + 2)
+ {
+ chargeFeeRetDefault.Output.Success.ShouldBe(true);
+
+ //no change
+ var afterBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = DefaultSender
+ });
+ afterBalance.Balance.ShouldBe(10);
+
+ //no change
+ var afterDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = DelegateeAddress
+ });
+ afterDelegateeBalance.Balance.ShouldBe(20);
+
+ var afterSecondaryDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = Delegatee2Address
+ });
+ afterSecondaryDelegateeBalance.Balance.ShouldBe(afterBalanceDelegatee);
+ var delegation = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = Delegatee2Address,
+ DelegatorAddress = DelegateeAddress,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ delegation.Delegations[basicFeeSymbol].ShouldBe(afterDelegateeAmount);
+ }
+ else
+ {
+ chargeFeeRetDefault.Output.Success.ShouldBe(false);
+
+ var delegation = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = DefaultSender,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ delegation.Delegations[NativeTokenSymbol].ShouldBe(5);
+ var delegation2 = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = Delegatee2Address,
+ DelegatorAddress = DelegateeAddress,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ delegation2.Delegations[basicFeeSymbol].ShouldBe(delegateeAmountBasic);
+ }
+ }
+
+ [Theory]
+ [InlineData(10, 20, 70, 1000, 1000, 1000, 10, 10, 20, 20, 70, 70, 80, 80, 70, 1000)]
+ public async Task ChargeTransactionFee_DelegationNew_Second_Failed_DelegateeBalanceIsNotEnough(
+ long initialBalance, long initialDelegateeBalance, long initialDelegatee2Balance,
+ long delegateeAmountNativeToken, long delegateeAmountBasic, long delegateeAmountSize,
+ long baseFeeBalance, long sizeFeeBalance, long baseFeeDelegateBalance, long sizeFeeDelegateBalance,
+ long baseFeeDelegate2Balance, long sizeFeeDelegate2Balance,
+ long basicFee, long sizeFee, long afterBalanceDelegatee, long afterDelegateeAmount)
+ {
+ var basicFeeSymbol = "BASIC";
+ var sizeFeeSymbol = "SIZE";
+
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAsync(DefaultSender, basicFeeSymbol);
+ await CreateTokenAsync(DefaultSender, sizeFeeSymbol);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialBalance);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegateeBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegatee2Balance, Delegatee2Address);
+ if (baseFeeBalance != 0 && sizeFeeBalance != 0 &&
+ baseFeeDelegateBalance != 0 && sizeFeeDelegateBalance != 0 &&
+ baseFeeDelegate2Balance != 0 && sizeFeeDelegate2Balance != 0)
+ {
+ await IssueTokenToDefaultSenderAsync(basicFeeSymbol, baseFeeBalance);
+ await IssueTokenToDefaultSenderAsync(sizeFeeSymbol, sizeFeeBalance);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegate2Balance, Delegatee2Address);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegate2Balance, Delegatee2Address);
+ }
+
+ var delegations = new Dictionary
+ {
+ [NativeTokenSymbol] = 5,
+ };
+ var delegations2 = new Dictionary
+ {
+ [NativeTokenSymbol] = delegateeAmountNativeToken,
+ [basicFeeSymbol] = delegateeAmountBasic,
+ [sizeFeeSymbol] = delegateeAmountSize
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ Delegations = { delegations },
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ };
+ var delegateInfo2 = new DelegateInfo
+ {
+ Delegations = { delegations2 },
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ };
+ await TokenContractStubDelegate1.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DefaultSender,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ await TokenContractStubDelegate2.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DelegateeAddress,
+ DelegateInfoList = { delegateInfo2 }
+ });
+
+ var sizeFeeSymbolList = await SetMethodOrSizeFeeAsync(basicFeeSymbol, sizeFeeSymbol, 80);
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = sizeFee,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+ var delegationResult =
+ await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = DefaultSender,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ var delegationResult2 =
+ await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = Delegatee2Address,
+ DelegatorAddress = DelegateeAddress,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ var chargeFeeRetDefault = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ if (chargeFeeRetDefault.Transaction.RefBlockNumber >= delegationResult.BlockHeight + 2 &&
+ chargeFeeRetDefault.Transaction.RefBlockNumber >= delegationResult2.BlockHeight + 2)
+ {
+ chargeFeeRetDefault.Output.Success.ShouldBe(false);
+ chargeFeeRetDefault.Output.ChargingInformation.ShouldBe("Transaction fee not enough.");
+
+ //all in
+ var afterBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = DefaultSender
+ });
+ afterBalance.Balance.ShouldBe(0);
+
+ //no change
+ var afterDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = DelegateeAddress
+ });
+ afterDelegateeBalance.Balance.ShouldBe(20);
+
+ //no change
+ var afterSecondaryDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = Delegatee2Address
+ });
+ afterSecondaryDelegateeBalance.Balance.ShouldBe(afterBalanceDelegatee);
+ var delegation = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = Delegatee2Address,
+ DelegatorAddress = DelegateeAddress,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ delegation.Delegations[basicFeeSymbol].ShouldBe(afterDelegateeAmount);
+ }
+ else
+ {
+ chargeFeeRetDefault.Output.Success.ShouldBe(false);
+ }
+ }
+
+ [Theory]
+ [InlineData(10, 20, 100, 30, 30, 30, 10, 10, 20, 20, 100, 100, 80, 80, 100, 30)]
+ public async Task ChargeTransactionFee_DelegationNew_Second_Failed_DelegationIsNotEnough(
+ long initialBalance, long initialDelegateeBalance, long initialDelegatee2Balance,
+ long delegateeAmountNativeToken, long delegateeAmountBasic, long delegateeAmountSize,
+ long baseFeeBalance, long sizeFeeBalance, long baseFeeDelegateBalance, long sizeFeeDelegateBalance,
+ long baseFeeDelegate2Balance, long sizeFeeDelegate2Balance,
+ long basicFee, long sizeFee, long afterBalanceDelegatee, long afterDelegateeAmount)
+ {
+ var basicFeeSymbol = "BASIC";
+ var sizeFeeSymbol = "SIZE";
+
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAsync(DefaultSender, basicFeeSymbol);
+ await CreateTokenAsync(DefaultSender, sizeFeeSymbol);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialBalance);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegateeBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegatee2Balance, Delegatee2Address);
+ if (baseFeeBalance != 0 && sizeFeeBalance != 0 &&
+ baseFeeDelegateBalance != 0 && sizeFeeDelegateBalance != 0 &&
+ baseFeeDelegate2Balance != 0 && sizeFeeDelegate2Balance != 0)
+ {
+ await IssueTokenToDefaultSenderAsync(basicFeeSymbol, baseFeeBalance);
+ await IssueTokenToDefaultSenderAsync(sizeFeeSymbol, sizeFeeBalance);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegate2Balance, Delegatee2Address);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegate2Balance, Delegatee2Address);
+ }
+
+ var delegations = new Dictionary
+ {
+ [NativeTokenSymbol] = 5,
+ };
+ var delegations2 = new Dictionary
+ {
+ [NativeTokenSymbol] = delegateeAmountNativeToken,
+ [basicFeeSymbol] = delegateeAmountBasic,
+ [sizeFeeSymbol] = delegateeAmountSize
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ Delegations = { delegations },
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ };
+ var delegateInfo2 = new DelegateInfo
+ {
+ Delegations = { delegations2 },
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ };
+ await TokenContractStubDelegate1.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DefaultSender,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ await TokenContractStubDelegate2.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DelegateeAddress,
+ DelegateInfoList = { delegateInfo2 }
+ });
+
+ var sizeFeeSymbolList = await SetMethodOrSizeFeeAsync(basicFeeSymbol, sizeFeeSymbol, 80);
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = sizeFee,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+ var chargeFeeRetDefault = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRetDefault.Output.Success.ShouldBe(false);
+
+ //no change
+ var afterBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = DefaultSender
+ });
+ afterBalance.Balance.ShouldBe(0);
+
+ //no change
+ var afterDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = DelegateeAddress
+ });
+ afterDelegateeBalance.Balance.ShouldBe(20);
+
+ var afterSecondaryDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = Delegatee2Address
+ });
+ afterSecondaryDelegateeBalance.Balance.ShouldBe(afterBalanceDelegatee);
+ var delegation = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = Delegatee2Address,
+ DelegatorAddress = DelegateeAddress,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ delegation.Delegations[basicFeeSymbol].ShouldBe(afterDelegateeAmount);
+ }
+
+ [Theory]
+ [InlineData(10, 20, 100, 1000, 1000, 1000, 10, 10, 20, 20, 100, 100, 80, 80, 100, 1000)]
+ public async Task ChargeTransactionFee_DelegationNew_Second_Failed_DelegateIsNotExist(
+ long initialBalance, long initialDelegateeBalance, long initialDelegatee2Balance,
+ long delegateeAmountNativeToken, long delegateeAmountBasic, long delegateeAmountSize,
+ long baseFeeBalance, long sizeFeeBalance, long baseFeeDelegateBalance, long sizeFeeDelegateBalance,
+ long baseFeeDelegate2Balance, long sizeFeeDelegate2Balance,
+ long basicFee, long sizeFee, long afterBalanceDelegatee, long afterDelegateeAmount)
+ {
+ var basicFeeSymbol = "BASIC";
+ var sizeFeeSymbol = "SIZE";
+
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAsync(DefaultSender, basicFeeSymbol);
+ await CreateTokenAsync(DefaultSender, sizeFeeSymbol);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialBalance);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegateeBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegatee2Balance, Delegatee2Address);
+ if (baseFeeBalance != 0 && sizeFeeBalance != 0 &&
+ baseFeeDelegateBalance != 0 && sizeFeeDelegateBalance != 0 &&
+ baseFeeDelegate2Balance != 0 && sizeFeeDelegate2Balance != 0)
+ {
+ await IssueTokenToDefaultSenderAsync(basicFeeSymbol, baseFeeBalance);
+ await IssueTokenToDefaultSenderAsync(sizeFeeSymbol, sizeFeeBalance);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegate2Balance, Delegatee2Address);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegate2Balance, Delegatee2Address);
+ }
+
+ var delegations = new Dictionary
+ {
+ [NativeTokenSymbol] = 5,
+ };
+ var delegations2 = new Dictionary
+ {
+ [NativeTokenSymbol] = delegateeAmountNativeToken,
+ [basicFeeSymbol] = delegateeAmountBasic,
+ [sizeFeeSymbol] = delegateeAmountSize
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ Delegations = { delegations },
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ };
+ var delegateInfo2 = new DelegateInfo
+ {
+ Delegations = { delegations2 },
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = ConsensusContractAddress,
+ };
+ await TokenContractStubDelegate1.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DefaultSender,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ await TokenContractStubDelegate2.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DelegateeAddress,
+ DelegateInfoList = { delegateInfo2 }
+ });
+
+ var sizeFeeSymbolList = await SetMethodOrSizeFeeAsync(basicFeeSymbol, sizeFeeSymbol, basicFee);
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = sizeFee,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+ var chargeFeeRetDefault = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRetDefault.Output.Success.ShouldBe(false);
+
+ //no change
+ var afterBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = DefaultSender
+ });
+ afterBalance.Balance.ShouldBe(0);
+
+ //no change
+ var afterDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = DelegateeAddress
+ });
+ afterDelegateeBalance.Balance.ShouldBe(20);
+
+ var afterSecondaryDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = Delegatee2Address
+ });
+ afterSecondaryDelegateeBalance.Balance.ShouldBe(afterBalanceDelegatee);
+ var delegation = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = Delegatee2Address,
+ DelegatorAddress = DelegateeAddress,
+ ContractAddress = ConsensusContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ delegation.Delegations[basicFeeSymbol].ShouldBe(afterDelegateeAmount);
+ }
+
+ [Theory]
+ [InlineData(10, 20, 100, 1000, 1000, 1000, 10, 10, 20, 20, 100, 100, 80, 80, 20, 920)]
+ public async Task ChargeTransactionFee_DelegationOldFirst_NewSecond_Success(
+ long initialBalance, long initialDelegateeBalance, long initialDelegatee2Balance,
+ long delegateeAmountNativeToken, long delegateeAmountBasic, long delegateeAmountSize,
+ long baseFeeBalance, long sizeFeeBalance, long baseFeeDelegateBalance, long sizeFeeDelegateBalance,
+ long baseFeeDelegate2Balance, long sizeFeeDelegate2Balance,
+ long basicFee, long sizeFee, long afterBalanceDelegatee, long afterDelegateeAmount)
+ {
+ var basicFeeSymbol = "BASIC";
+ var sizeFeeSymbol = "SIZE";
+
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAsync(DefaultSender, basicFeeSymbol);
+ await CreateTokenAsync(DefaultSender, sizeFeeSymbol);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialBalance);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegateeBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegatee2Balance, Delegatee2Address);
+ if (baseFeeBalance != 0 && sizeFeeBalance != 0 &&
+ baseFeeDelegateBalance != 0 && sizeFeeDelegateBalance != 0 &&
+ baseFeeDelegate2Balance != 0 && sizeFeeDelegate2Balance != 0)
+ {
+ await IssueTokenToDefaultSenderAsync(basicFeeSymbol, baseFeeBalance);
+ await IssueTokenToDefaultSenderAsync(sizeFeeSymbol, sizeFeeBalance);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegate2Balance, Delegatee2Address);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegate2Balance, Delegatee2Address);
+ }
+
+ var delegations = new Dictionary
+ {
+ [NativeTokenSymbol] = 5,
+ };
+ var delegations2 = new Dictionary
+ {
+ [NativeTokenSymbol] = delegateeAmountNativeToken,
+ [basicFeeSymbol] = delegateeAmountBasic,
+ [sizeFeeSymbol] = delegateeAmountSize
+ };
+ var delegateInfo2 = new DelegateInfo
+ {
+ Delegations = { delegations2 },
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ };
+ await TokenContractStubDelegate1.SetTransactionFeeDelegations.SendAsync(
+ new SetTransactionFeeDelegationsInput
+ {
+ DelegatorAddress = DefaultSender,
+ Delegations = { delegations }
+ });
+ await TokenContractStubDelegate2.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DelegateeAddress,
+ DelegateInfoList = { delegateInfo2 }
+ });
+
+ var sizeFeeSymbolList = await SetMethodOrSizeFeeAsync(basicFeeSymbol, sizeFeeSymbol, basicFee);
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = sizeFee,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+ var delegationResult =
+ await TokenContractStubDelegate1.GetTransactionFeeDelegationsOfADelegatee.CallAsync(
+ new GetTransactionFeeDelegationsOfADelegateeInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = DefaultSender
+ });
+ var delegationResult2 =
+ await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = Delegatee2Address,
+ DelegatorAddress = DelegateeAddress,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ var chargeFeeRetDefault = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ if (chargeFeeRetDefault.Transaction.RefBlockNumber >= delegationResult.BlockHeight + 2 &&
+ chargeFeeRetDefault.Transaction.RefBlockNumber >= delegationResult2.BlockHeight + 2)
+ {
+ chargeFeeRetDefault.Output.Success.ShouldBe(true);
+
+ //no change
+ var afterBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = DefaultSender
+ });
+ afterBalance.Balance.ShouldBe(10);
+
+ //no change
+ var afterDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = DelegateeAddress
+ });
+ afterDelegateeBalance.Balance.ShouldBe(20);
+
+ var afterSecondaryDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = Delegatee2Address
+ });
+ afterSecondaryDelegateeBalance.Balance.ShouldBe(afterBalanceDelegatee);
+ var delegation = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = Delegatee2Address,
+ DelegatorAddress = DelegateeAddress,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ delegation.Delegations[basicFeeSymbol].ShouldBe(afterDelegateeAmount);
+ }
+ else
+ {
+ chargeFeeRetDefault.Output.Success.ShouldBe(false);
+
+ var delegation = await TokenContractStubDelegate1.GetTransactionFeeDelegationsOfADelegatee.CallAsync(
+ new GetTransactionFeeDelegationsOfADelegateeInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = DefaultSender
+ });
+ delegation.Delegations[NativeTokenSymbol].ShouldBe(5);
+ var delegation2 = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = Delegatee2Address,
+ DelegatorAddress = DelegateeAddress,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ delegation2.Delegations[basicFeeSymbol].ShouldBe(delegateeAmountBasic);
+ }
+ }
+
+ [Theory]
+ [InlineData(10, 20, 100, 10, 10, 20, 20, 100, 100, 80, 80, 20)]
+ public async Task ChargeTransactionFee_DelegationNew_UnlimitedDelegate_Success(
+ long initialBalance, long initialDelegateeBalance, long initialDelegatee2Balance,
+ long baseFeeBalance, long sizeFeeBalance, long baseFeeDelegateBalance, long sizeFeeDelegateBalance,
+ long baseFeeDelegate2Balance, long sizeFeeDelegate2Balance,
+ long basicFee, long sizeFee, long afterBalanceDelegatee)
+ {
+ var basicFeeSymbol = "BASIC";
+ var sizeFeeSymbol = "SIZE";
+
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAsync(DefaultSender, basicFeeSymbol);
+ await CreateTokenAsync(DefaultSender, sizeFeeSymbol);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialBalance);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegateeBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialDelegatee2Balance, Delegatee2Address);
+ if (baseFeeBalance != 0 && sizeFeeBalance != 0 &&
+ baseFeeDelegateBalance != 0 && sizeFeeDelegateBalance != 0 &&
+ baseFeeDelegate2Balance != 0 && sizeFeeDelegate2Balance != 0)
+ {
+ await IssueTokenToDefaultSenderAsync(basicFeeSymbol, baseFeeBalance);
+ await IssueTokenToDefaultSenderAsync(sizeFeeSymbol, sizeFeeBalance);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegateBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(basicFeeSymbol, baseFeeDelegate2Balance, Delegatee2Address);
+ await IssueTokenToUserAsync(sizeFeeSymbol, sizeFeeDelegate2Balance, Delegatee2Address);
+ }
+
+ var delegations = new Dictionary
+ {
+ [NativeTokenSymbol] = 5,
+ };
+ var delegateInfo2 = new DelegateInfo
+ {
+ IsUnlimitedDelegate = true,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ };
+ await TokenContractStubDelegate1.SetTransactionFeeDelegations.SendAsync(
+ new SetTransactionFeeDelegationsInput
+ {
+ DelegatorAddress = DefaultSender,
+ Delegations = { delegations }
+ });
+ await TokenContractStubDelegate2.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DelegateeAddress,
+ DelegateInfoList = { delegateInfo2 }
+ });
+
+ var sizeFeeSymbolList = await SetMethodOrSizeFeeAsync(basicFeeSymbol, sizeFeeSymbol, basicFee);
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = sizeFee,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+ var delegationResult =
+ await TokenContractStubDelegate1.GetTransactionFeeDelegationsOfADelegatee.CallAsync(
+ new GetTransactionFeeDelegationsOfADelegateeInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = DefaultSender
+ });
+ var delegationResult2 =
+ await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = Delegatee2Address,
+ DelegatorAddress = DelegateeAddress,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ var chargeFeeRetDefault = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ if (chargeFeeRetDefault.Transaction.RefBlockNumber >= delegationResult.BlockHeight + 2 &&
+ chargeFeeRetDefault.Transaction.RefBlockNumber >= delegationResult2.BlockHeight + 2)
+ {
+ chargeFeeRetDefault.Output.Success.ShouldBe(true);
+
+ //no change
+ var afterBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = DefaultSender
+ });
+ afterBalance.Balance.ShouldBe(10);
+
+ //no change
+ var afterDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = DelegateeAddress
+ });
+ afterDelegateeBalance.Balance.ShouldBe(20);
+
+ var afterSecondaryDelegateeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = basicFeeSymbol,
+ Owner = Delegatee2Address
+ });
+ afterSecondaryDelegateeBalance.Balance.ShouldBe(afterBalanceDelegatee);
+ }
+ else
+ {
+ chargeFeeRetDefault.Output.Success.ShouldBe(false);
+
+ var delegation = await TokenContractStubDelegate1.GetTransactionFeeDelegationsOfADelegatee.CallAsync(
+ new GetTransactionFeeDelegationsOfADelegateeInput
+ {
+ DelegateeAddress = DelegateeAddress,
+ DelegatorAddress = DefaultSender
+ });
+ delegation.Delegations[NativeTokenSymbol].ShouldBe(5);
+ }
+ }
+
+ [Fact]
+ public async Task ChargeTransactionFee_DelegationNew_MultiDelegate_Success()
+ {
+ var basicFeeSymbol = "BASIC";
+ var sizeFeeSymbol = "SIZE";
+
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAsync(DefaultSender, basicFeeSymbol);
+ await CreateTokenAsync(DefaultSender, sizeFeeSymbol);
+
+ var tokenList = new List { NativeTokenSymbol, basicFeeSymbol, sizeFeeSymbol };
+ await IssueTokenListToUserAsync(tokenList, 10, DefaultSender);
+ await IssueTokenListToUserAsync(tokenList, 20, DelegateeAddress);
+ await IssueTokenListToUserAsync(tokenList, 100, Delegatee2Address);
+ await IssueTokenListToUserAsync(tokenList, 20, Delegatee3Address);
+ await IssueTokenListToUserAsync(tokenList, 20, SecondaryDelegatee1Address);
+ await IssueTokenListToUserAsync(tokenList, 100, SecondaryDelegatee2Address);
+ await IssueTokenListToUserAsync(tokenList, 20, SecondaryDelegatee3Address);
+ await IssueTokenListToUserAsync(tokenList, 20, SecondaryDelegatee4Address);
+ await IssueTokenListToUserAsync(tokenList, 200, SecondaryDelegatee5Address);
+ await IssueTokenListToUserAsync(tokenList, 100, SecondaryDelegatee6Address);
+
+ //first delegate
+ //delegatee1 -> default sender, balance is not enough
+ //delegatee2 -> default sender, delegation is not enough
+ //delegatee3 -> default sender, balance and delegation is not enough
+ var delegations1 = new Dictionary
+ {
+ [NativeTokenSymbol] = 100,
+ [basicFeeSymbol] = 100,
+ [sizeFeeSymbol] = 100,
+ };
+ var delegations2 = new Dictionary
+ {
+ [NativeTokenSymbol] = 10
+ };
+ var delegations3 = new Dictionary
+ {
+ [NativeTokenSymbol] = 30,
+ [basicFeeSymbol] = 100
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ Delegations = { delegations1 }
+ };
+ var delegateInfo2 = new DelegateInfo
+ {
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ Delegations = { delegations2 }
+ };
+ var delegateInfo3 = new DelegateInfo
+ {
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ Delegations = { delegations3 }
+ };
+ await TokenContractStubDelegate1.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DefaultSender,
+ DelegateInfoList = { delegateInfo1 },
+ });
+ await TokenContractStubDelegate2.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DefaultSender,
+ DelegateInfoList = { delegateInfo2 }
+ });
+ await TokenContractStubDelegate3.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DefaultSender,
+ DelegateInfoList = { delegateInfo3 }
+ });
+ //second delegate
+ //secondary delegatee1 -> delegatee1, balance is not enough
+ //secondary delegatee2 -> delegatee1, delegation is not enough
+ //secondary delegatee3 -> delegatee1, balance and delegation is not enough
+ //secondary delegatee4 -> delegatee2, balance is not enough
+ //secondary delegatee5 -> delegatee2, success
+ //secondary delegatee6 -> delegatee3
+ await TokenContractStubSecondaryDelegate1.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DelegateeAddress,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ await TokenContractStubSecondaryDelegate2.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DelegateeAddress,
+ DelegateInfoList = { delegateInfo2 }
+ });
+ await TokenContractStubSecondaryDelegate3.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DelegateeAddress,
+ DelegateInfoList = { delegateInfo3 }
+ });
+ await TokenContractStubSecondaryDelegate4.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = Delegatee2Address,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ await TokenContractStubSecondaryDelegate5.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = Delegatee2Address,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ await TokenContractStubSecondaryDelegate6.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = Delegatee3Address,
+ DelegateInfoList = { delegateInfo3 }
+ });
+
+ var sizeFeeSymbolList = await SetMethodOrSizeFeeAsync(basicFeeSymbol, sizeFeeSymbol, 80);
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = 80,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+
+ var delegateList = new List<(Address, Address)>
+ {
+ (DelegateeAddress, DefaultSender),
+ (Delegatee2Address, DefaultSender),
+ (Delegatee3Address, DefaultSender),
+ (SecondaryDelegatee1Address, DelegateeAddress),
+ (SecondaryDelegatee2Address, DelegateeAddress),
+ (SecondaryDelegatee3Address, DelegateeAddress),
+ (SecondaryDelegatee4Address, Delegatee2Address),
+ (SecondaryDelegatee5Address, Delegatee2Address),
+ (SecondaryDelegatee6Address, Delegatee3Address),
+ (DelegateeAddress, DefaultSender),
+ (DelegateeAddress, DefaultSender),
+ (DelegateeAddress, DefaultSender)
+ };
+
+ var chargeFeeRetDefault = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ var result = await GetSetDelegationResultAsync(delegateList, chargeFeeRetDefault.Transaction.RefBlockNumber);
+ if (result)
+ {
+ chargeFeeRetDefault.Output.Success.ShouldBe(true);
+ await CheckUserBalanceAsync(NativeTokenSymbol, DefaultSender, 10);
+ await CheckUserBalanceAsync(basicFeeSymbol, DelegateeAddress, 20);
+ await CheckUserBalanceAsync(basicFeeSymbol, Delegatee2Address, 100);
+ await CheckUserBalanceAsync(NativeTokenSymbol, Delegatee3Address, 20);
+ await CheckUserBalanceAsync(basicFeeSymbol, SecondaryDelegatee1Address, 20);
+ await CheckUserBalanceAsync(basicFeeSymbol, SecondaryDelegatee2Address, 100);
+ await CheckUserBalanceAsync(NativeTokenSymbol, SecondaryDelegatee3Address, 20);
+ await CheckUserBalanceAsync(NativeTokenSymbol, SecondaryDelegatee4Address, 20);
+ //change
+ await CheckUserBalanceAsync(basicFeeSymbol, SecondaryDelegatee5Address, 120);
+ await CheckUserBalanceAsync(NativeTokenSymbol, SecondaryDelegatee6Address, 100);
+ var delegateInfo =
+ await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = SecondaryDelegatee5Address,
+ DelegatorAddress = Delegatee2Address,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ delegateInfo.Delegations[basicFeeSymbol].ShouldBe(20);
+ var delegation = await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = SecondaryDelegatee3Address,
+ DelegatorAddress = DelegateeAddress,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ delegation.Delegations[NativeTokenSymbol].ShouldBe(30);
+ delegation.Delegations[basicFeeSymbol].ShouldBe(100);
+ }
+ else
+ {
+ chargeFeeRetDefault.Output.Success.ShouldBe(false);
+ var delegateInfo =
+ await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = SecondaryDelegatee5Address,
+ DelegatorAddress = Delegatee2Address,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ delegateInfo.Delegations[basicFeeSymbol].ShouldBe(100);
+ }
+ }
+
+ [Fact]
+ public async Task SetPrimaryTokenSymbol_InvalidInput_Test()
+ {
+ {
+ var result =
+ await TokenContractStub.SetPrimaryTokenSymbol.SendWithExceptionAsync(new SetPrimaryTokenSymbolInput());
+ result.TransactionResult.Error.ShouldContain("Invalid input symbol.");
+ }
+ {
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, 1000000);
+ var result = await TokenContractStub.Transfer.SendWithExceptionAsync(new TransferInput
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = 100
+ });
+ result.TransactionResult.Error.ShouldContain("Invalid input address.");
+ }
+ {
+ var result = await TokenContractStub.Lock.SendWithExceptionAsync(new LockInput());
+ result.TransactionResult.Error.ShouldContain("Invalid input symbol.");
+ }
+ {
+ var result = await TokenContractStub.Lock.SendWithExceptionAsync(new LockInput
+ {
+ Symbol = NativeTokenSymbol
+ });
+ result.TransactionResult.Error.ShouldContain("Invalid input address.");
+ }
+ {
+ var result = await TokenContractStub.Unlock.SendWithExceptionAsync(new UnlockInput());
+ result.TransactionResult.Error.ShouldContain("Invalid input symbol.");
+ }
+ {
+ var result = await TokenContractStub.Unlock.SendWithExceptionAsync(new UnlockInput
+ {
+ Symbol = NativeTokenSymbol
+ });
+ result.TransactionResult.Error.ShouldContain("Invalid input address.");
+ }
+ {
+ var result = await TokenContractStub.TransferFrom.SendWithExceptionAsync(new TransferFromInput
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = 100
+ });
+ result.TransactionResult.Error.ShouldContain("Invalid input address.");
+ }
+ {
+ var result = await TokenContractStub.TransferFrom.SendWithExceptionAsync(new TransferFromInput
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = 100,
+ From = DefaultSender
+ });
+ result.TransactionResult.Error.ShouldContain("Invalid input address.");
+ }
+ {
+ var result = await TokenContractStub.Approve.SendWithExceptionAsync(new ApproveInput());
+ result.TransactionResult.Error.ShouldContain("Invalid input address.");
+ }
+ {
+ var result = await TokenContractStub.UnApprove.SendWithExceptionAsync(new UnApproveInput());
+ result.TransactionResult.Error.ShouldContain("Invalid input address.");
+ }
+ {
+ var result = await TokenContractStub.CheckThreshold.SendWithExceptionAsync(new CheckThresholdInput());
+ result.TransactionResult.Error.ShouldContain("Invalid input address.");
+ }
+ {
+ var result =
+ await TokenContractImplStub.AdvanceResourceToken
+ .SendWithExceptionAsync(new AdvanceResourceTokenInput());
+ result.TransactionResult.Error.ShouldContain("Invalid input address.");
+ }
+ {
+ var result =
+ await TokenContractImplStub.TakeResourceTokenBack.SendWithExceptionAsync(
+ new TakeResourceTokenBackInput());
+ result.TransactionResult.Error.ShouldContain("Invalid input resource token symbol.");
+ }
+ {
+ var result = await TokenContractImplStub.TakeResourceTokenBack.SendWithExceptionAsync(
+ new TakeResourceTokenBackInput
+ {
+ ResourceTokenSymbol = NativeTokenSymbol
+ });
+ result.TransactionResult.Error.ShouldContain("Invalid input address.");
+ }
+ {
+ var result =
+ await TokenContractImplStub.ValidateTokenInfoExists.SendWithExceptionAsync(
+ new ValidateTokenInfoExistsInput());
+ result.TransactionResult.Error.ShouldContain("Invalid input symbol.");
+ }
+ {
+ var result =
+ await TokenContractImplStub.SetTransactionFeeDelegations.SendWithExceptionAsync(
+ new SetTransactionFeeDelegationsInput());
+ result.TransactionResult.Error.ShouldContain("Invalid input address.");
+ }
+ {
+ var result =
+ await TokenContractImplStub.SetTransactionFeeDelegations.SendWithExceptionAsync(
+ new SetTransactionFeeDelegationsInput());
+ result.TransactionResult.Error.ShouldContain("Invalid input address.");
+ }
+ {
+ var result =
+ await TokenContractImplStub.UpdateCoefficientsForContract.SendWithExceptionAsync(
+ new UpdateCoefficientsInput());
+ result.TransactionResult.Error.ShouldContain("Invalid input coefficients.");
+ }
+ {
+ var result =
+ await TokenContractImplStub.UpdateCoefficientsForSender.SendWithExceptionAsync(
+ new UpdateCoefficientsInput());
+ result.TransactionResult.Error.ShouldContain("Invalid input coefficients.");
+ }
+ }
+
+ private async Task IssueTokenListToUserAsync(List symbols, long amount, Address address)
+ {
+ foreach (var symbol in symbols)
+ {
+ await IssueTokenToUserAsync(symbol, amount, address);
+ }
+ }
+
+ private async Task GetSetDelegationResultAsync(List<(Address, Address)> delegateAddressList,
+ long refBlockHeight)
+ {
+ var result = true;
+ foreach (var (delegateeAddress, delegatorAddress) in delegateAddressList)
+ {
+ var delegateInfo =
+ await TokenContractStubDelegate1.GetTransactionFeeDelegateInfo.CallAsync(
+ new GetTransactionFeeDelegateInfoInput
+ {
+ DelegateeAddress = delegateeAddress,
+ DelegatorAddress = delegatorAddress,
+ ContractAddress = TokenContractAddress,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer)
+ });
+ result = result && refBlockHeight >= delegateInfo.BlockHeight + 2;
+ }
+
+ return result;
+ }
+
+ private async Task CheckUserBalanceAsync(string symbol, Address owner, long balance)
+ {
+ var userBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = symbol,
+ Owner = owner
+ });
+ userBalance.Balance.ShouldBe(balance);
+ }
+
+ private async Task SetMethodOrSizeFeeAsync(string basicFeeSymbol, string sizeFeeSymbol,
+ long basicFee)
+ {
+ var methodFee = new MethodFees
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ Fees =
+ {
+ new MethodFee
+ {
+ Symbol = basicFeeSymbol,
+ BasicFee = basicFee
+ }
+ }
+ };
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
+
+ var sizeFeeSymbolList = new SymbolListToPayTxSizeFee
+ {
+ SymbolsToPayTxSizeFee =
+ {
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = sizeFeeSymbol,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ },
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = NativeTokenSymbol,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ }
+ }
+ };
+
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
+
+ return sizeFeeSymbolList;
+ }
+
+
+ private async Task GetTokenSupplyAmount(string tokenSymbol)
+ {
+ var tokenInfo = await TokenContractStub.GetTokenInfo.CallAsync(new GetTokenInfoInput
+ {
+ Symbol = tokenSymbol
+ });
+ return tokenInfo.Supply;
+ }
+
+ private async Task> GetDefaultBalancesAsync(string[] tokenSymbolList)
+ {
+ var balances = new List();
+ foreach (var symbol in tokenSymbolList)
+ balances.Add(await GetBalanceAsync(DefaultSender, symbol));
+ return balances;
+ }
+
+ private async Task CreateTokenAsync(Address creator, string tokenSymbol, bool isBurned = true)
+ {
+ await TokenContractStub.Create.SendAsync(new CreateInput
+ {
+ Symbol = tokenSymbol,
+ TokenName = tokenSymbol + " name",
+ TotalSupply = 1000_00000000,
+ IsBurnable = isBurned,
+ Issuer = creator,
+ Owner = creator
+ });
+ }
+
+ private async Task IssueTokenToDefaultSenderAsync(string tokenSymbol, long amount)
+ {
+ if (amount <= 0) return;
+ var issueResult = await TokenContractStub.Issue.SendAsync(new IssueInput()
+ {
+ Symbol = tokenSymbol,
+ Amount = amount,
+ To = DefaultSender,
+ });
+ issueResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ }
+
+ private async Task IssueTokenToUserAsync(string tokenSymbol, long amount, Address to)
+ {
+ var issueResult = await TokenContractStub.Issue.SendAsync(new IssueInput()
+ {
+ Symbol = tokenSymbol,
+ Amount = amount,
+ To = to,
+ });
+ issueResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
}
private async Task GetBalanceAsync(Address address, string tokenSymbol)
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutePluginTransactionDirectlyTest_FreeAllowance.cs b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutePluginTransactionDirectlyTest_FreeAllowance.cs
new file mode 100644
index 0000000000..0cdb3ab91e
--- /dev/null
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutePluginTransactionDirectlyTest_FreeAllowance.cs
@@ -0,0 +1,2047 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using AElf.Contracts.MultiToken;
+using AElf.CSharp.Core.Extension;
+using AElf.Standards.ACS1;
+using AElf.Types;
+using Google.Protobuf.WellKnownTypes;
+using Shouldly;
+using Xunit;
+
+namespace AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests;
+
+public partial class ExecutePluginTransactionDirectlyTest
+{
+ [Fact]
+ public async Task ConfigTransactionFeeFreeAllowances_Test()
+ {
+ await SetPrimaryTokenSymbolAsync();
+
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = 0
+ }
+ }
+ },
+ RefreshSeconds = 600,
+ Threshold = 0
+ }
+ }
+ });
+
+ {
+ var config = await TokenContractImplStub.GetTransactionFeeFreeAllowancesConfig.CallAsync(new Empty());
+ config.Value.Count.ShouldBe(1);
+ config.Value.First().Symbol.ShouldBe(NativeTokenSymbol);
+ config.Value.First().Threshold.ShouldBe(0);
+ config.Value.First().RefreshSeconds.ShouldBe(600);
+ config.Value.First().FreeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ config.Value.First().FreeAllowances.Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ config.Value.First().FreeAllowances.Map.Values.First().Amount.ShouldBe(0);
+
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(0);
+ }
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, 2_00000000);
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = 1_00000000
+ }
+ }
+ },
+ RefreshSeconds = 600,
+ Threshold = 1_00000000
+ }
+ }
+ });
+
+ {
+ var config = await TokenContractImplStub.GetTransactionFeeFreeAllowancesConfig.CallAsync(new Empty());
+ config.Value.Count.ShouldBe(1);
+ config.Value.First().Symbol.ShouldBe(NativeTokenSymbol);
+ config.Value.First().Threshold.ShouldBe(1_00000000);
+ config.Value.First().RefreshSeconds.ShouldBe(600);
+ config.Value.First().FreeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ config.Value.First().FreeAllowances.Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ config.Value.First().FreeAllowances.Map.Values.First().Amount.ShouldBe(1_00000000);
+
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(1_00000000);
+ }
+ }
+
+ [Fact]
+ public async Task ConfigTransactionFeeFreeAllowances_Unauthorized_Test()
+ {
+ var result =
+ await TokenContractImplStub2.ConfigTransactionFeeFreeAllowances.SendWithExceptionAsync(
+ new ConfigTransactionFeeFreeAllowancesInput());
+ result.TransactionResult.Error.ShouldContain("Unauthorized behavior.");
+ }
+
+ [Fact]
+ public async Task ConfigTransactionFeeFreeAllowances_MultipleTokens_OneByOne_Test()
+ {
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAndIssueAsync();
+
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = 1_00000000
+ }
+ }
+ },
+ RefreshSeconds = 600,
+ Threshold = 1_00000000
+ }
+ }
+ });
+
+ {
+ var config = await TokenContractImplStub.GetTransactionFeeFreeAllowancesConfig.CallAsync(new Empty());
+ config.Value.Count.ShouldBe(1);
+ config.Value.First().Symbol.ShouldBe(NativeTokenSymbol);
+ config.Value.First().Threshold.ShouldBe(1_00000000);
+ config.Value.First().RefreshSeconds.ShouldBe(600);
+ config.Value.First().FreeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ config.Value.First().FreeAllowances.Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ config.Value.First().FreeAllowances.Map.Values.First().Amount.ShouldBe(1_00000000);
+
+ var userAFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserAAddress);
+ userAFreeAllowances.Result.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ userAFreeAllowances.Result.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ userAFreeAllowances.Result.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ userAFreeAllowances.Result.Map.Values.First().Map.Values.First().Amount.ShouldBe(1_00000000);
+ var userBFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserBAddress);
+ userBFreeAllowances.Result.Map.Count.ShouldBe(0);
+ var userCFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserCAddress);
+ userCFreeAllowances.Result.Map.ShouldBe(userAFreeAllowances.Result.Map);
+ }
+
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = USDT,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = 1_00000000
+ }
+ }
+ },
+ RefreshSeconds = 300,
+ Threshold = 1_000000
+ }
+ }
+ });
+
+ {
+ var config = await TokenContractImplStub.GetTransactionFeeFreeAllowancesConfig.CallAsync(new Empty());
+ config.Value.Count.ShouldBe(2);
+ config.Value.First().Symbol.ShouldBe(NativeTokenSymbol);
+ config.Value.First().Threshold.ShouldBe(1_00000000);
+ config.Value.First().RefreshSeconds.ShouldBe(600);
+ config.Value.First().FreeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ config.Value.First().FreeAllowances.Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ config.Value.First().FreeAllowances.Map.Values.First().Amount.ShouldBe(1_00000000);
+
+ config.Value.Last().Symbol.ShouldBe(USDT);
+ config.Value.Last().Threshold.ShouldBe(1_000000);
+ config.Value.Last().RefreshSeconds.ShouldBe(300);
+ config.Value.Last().FreeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ config.Value.Last().FreeAllowances.Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ config.Value.Last().FreeAllowances.Map.Values.First().Amount.ShouldBe(1_00000000);
+
+ var userAFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserAAddress);
+ userAFreeAllowances.Result.Map.Count.ShouldBe(1);
+ userAFreeAllowances.Result.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ userAFreeAllowances.Result.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ userAFreeAllowances.Result.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ userAFreeAllowances.Result.Map.Values.First().Map.Values.First().Amount.ShouldBe(1_00000000);
+ var userBFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserBAddress);
+ userBFreeAllowances.Result.Map.Count.ShouldBe(1);
+ userBFreeAllowances.Result.Map.Keys.First().ShouldBe(USDT);
+ userBFreeAllowances.Result.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ userBFreeAllowances.Result.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ userBFreeAllowances.Result.Map.Values.First().Map.Values.First().Amount.ShouldBe(1_00000000);
+ var userCFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserCAddress);
+ userAFreeAllowances.Result.Map.Add(USDT, userBFreeAllowances.Result.Map.Values.First());
+ userCFreeAllowances.Result.Map.ShouldBe(userAFreeAllowances.Result.Map);
+ }
+ }
+
+ [Fact]
+ public async Task ConfigTransactionFeeFreeAllowances_MultipleTokens_AtOnce_Test()
+ {
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAndIssueAsync();
+
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = 1_00000000
+ }
+ }
+ },
+ RefreshSeconds = 600,
+ Threshold = 1_00000000
+ },
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = USDT,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = 1_00000000
+ }
+ }
+ },
+ RefreshSeconds = 300,
+ Threshold = 1_000000
+ }
+ }
+ });
+
+ var config = await TokenContractImplStub.GetTransactionFeeFreeAllowancesConfig.CallAsync(new Empty());
+ config.Value.Count.ShouldBe(2);
+ config.Value.First().Symbol.ShouldBe(NativeTokenSymbol);
+ config.Value.First().Threshold.ShouldBe(1_00000000);
+ config.Value.First().RefreshSeconds.ShouldBe(600);
+ config.Value.First().FreeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ config.Value.First().FreeAllowances.Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ config.Value.First().FreeAllowances.Map.Values.First().Amount.ShouldBe(1_00000000);
+
+ config.Value.Last().Symbol.ShouldBe(USDT);
+ config.Value.Last().Threshold.ShouldBe(1_000000);
+ config.Value.Last().RefreshSeconds.ShouldBe(300);
+ config.Value.Last().FreeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ config.Value.Last().FreeAllowances.Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ config.Value.Last().FreeAllowances.Map.Values.First().Amount.ShouldBe(1_00000000);
+
+ var userAFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserAAddress);
+ userAFreeAllowances.Result.Map.Count.ShouldBe(1);
+ userAFreeAllowances.Result.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ userAFreeAllowances.Result.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ userAFreeAllowances.Result.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ userAFreeAllowances.Result.Map.Values.First().Map.Values.First().Amount.ShouldBe(1_00000000);
+ var userBFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserBAddress);
+ userBFreeAllowances.Result.Map.Count.ShouldBe(1);
+ userBFreeAllowances.Result.Map.Keys.First().ShouldBe(USDT);
+ userBFreeAllowances.Result.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ userBFreeAllowances.Result.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ userBFreeAllowances.Result.Map.Values.First().Map.Values.First().Amount.ShouldBe(1_00000000);
+ var userCFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserCAddress);
+ userAFreeAllowances.Result.Map.Add(USDT, userBFreeAllowances.Result.Map.Values.First());
+ userCFreeAllowances.Result.Map.ShouldBe(userAFreeAllowances.Result.Map);
+ }
+
+ [Fact]
+ public async Task ConfigTransactionFeeFreeAllowances_MultipleTokens_Modify_Test()
+ {
+ await ConfigTransactionFeeFreeAllowances_MultipleTokens_AtOnce_Test();
+ await CreateTokenAsync(DefaultSender, "ABC");
+
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = USDT,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = 2_00000000
+ },
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = "ABC",
+ Amount = 2_00000000
+ }
+ }
+ },
+ RefreshSeconds = 1200,
+ Threshold = 2_000000
+ }
+ }
+ });
+
+ var config = await TokenContractImplStub.GetTransactionFeeFreeAllowancesConfig.CallAsync(new Empty());
+ config.Value.Count.ShouldBe(2);
+ config.Value.First().Symbol.ShouldBe(NativeTokenSymbol);
+ config.Value.First().Threshold.ShouldBe(1_00000000);
+ config.Value.First().RefreshSeconds.ShouldBe(600);
+ config.Value.First().FreeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ config.Value.First().FreeAllowances.Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ config.Value.First().FreeAllowances.Map.Values.First().Amount.ShouldBe(1_00000000);
+
+ config.Value.Last().Symbol.ShouldBe(USDT);
+ config.Value.Last().Threshold.ShouldBe(2_000000);
+ config.Value.Last().RefreshSeconds.ShouldBe(1200);
+ config.Value.Last().FreeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ config.Value.Last().FreeAllowances.Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ config.Value.Last().FreeAllowances.Map.Values.First().Amount.ShouldBe(2_00000000);
+ config.Value.Last().FreeAllowances.Map.Keys.Last().ShouldBe("ABC");
+ config.Value.Last().FreeAllowances.Map.Values.Last().Symbol.ShouldBe("ABC");
+ config.Value.Last().FreeAllowances.Map.Values.Last().Amount.ShouldBe(2_00000000);
+
+ var userAFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserAAddress);
+ userAFreeAllowances.Result.Map.Count.ShouldBe(1);
+ userAFreeAllowances.Result.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ userAFreeAllowances.Result.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ userAFreeAllowances.Result.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ userAFreeAllowances.Result.Map.Values.First().Map.Values.First().Amount.ShouldBe(1_00000000);
+ var userBFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserBAddress);
+ userBFreeAllowances.Result.Map.Count.ShouldBe(0);
+ var userCFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserCAddress);
+ userCFreeAllowances.Result.Map.ShouldBe(userAFreeAllowances.Result.Map);
+ }
+
+ [Fact]
+ public async Task ConfigTransactionFeeFreeAllowances_InvalidInput_Test()
+ {
+ var message = await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendWithExceptionAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance()
+ }
+ });
+ message.TransactionResult.Error.ShouldContain("Invalid input symbol");
+
+ message = await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendWithExceptionAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = "TEST"
+ }
+ }
+ });
+ message.TransactionResult.Error.ShouldContain("Symbol TEST not exist");
+
+ message = await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendWithExceptionAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol
+ }
+ }
+ });
+ message.TransactionResult.Error.ShouldContain("Invalid input allowances");
+
+ message = await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendWithExceptionAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = 1_00000000
+ }
+ }
+ },
+ Threshold = -1
+ }
+ }
+ });
+ message.TransactionResult.Error.ShouldContain("Invalid input threshold");
+
+ message = await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendWithExceptionAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = 1_00000000
+ }
+ }
+ },
+ Threshold = 1_00000000,
+ RefreshSeconds = -1
+ }
+ }
+ });
+ message.TransactionResult.Error.ShouldContain("Invalid input refresh seconds");
+ }
+
+ [Fact]
+ public async Task RemoveTransactionFeeFreeAllowancesConfig_Unauthorized_Test()
+ {
+ var result = await TokenContractImplStub2.RemoveTransactionFeeFreeAllowancesConfig.SendWithExceptionAsync(
+ new RemoveTransactionFeeFreeAllowancesConfigInput());
+ result.TransactionResult.Error.ShouldContain("Unauthorized behavior.");
+ }
+
+ [Fact]
+ public async Task RemoveTransactionFeeFreeAllowancesConfig_Test()
+ {
+ await ConfigTransactionFeeFreeAllowances_MultipleTokens_AtOnce_Test();
+ await IssueTokenToUserAsync(USDT, 1_000000, UserAAddress);
+
+ var userAFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserAAddress);
+ userAFreeAllowances.Result.Map.Count.ShouldBe(2);
+ var config = TokenContractImplStub.GetTransactionFeeFreeAllowancesConfig.CallAsync(new Empty());
+ config.Result.Value.Count.ShouldBe(2);
+
+ await TokenContractImplStub.RemoveTransactionFeeFreeAllowancesConfig.SendAsync(
+ new RemoveTransactionFeeFreeAllowancesConfigInput
+ {
+ Symbols = { USDT }
+ });
+ config = TokenContractImplStub.GetTransactionFeeFreeAllowancesConfig.CallAsync(new Empty());
+ config.Result.Value.Count.ShouldBe(1);
+ config.Result.Value.First().Symbol.ShouldBe(NativeTokenSymbol);
+ userAFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserAAddress);
+ userAFreeAllowances.Result.Map.Count.ShouldBe(1);
+ userAFreeAllowances.Result.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+
+ // symbol not exist
+ await TokenContractImplStub.RemoveTransactionFeeFreeAllowancesConfig.SendAsync(
+ new RemoveTransactionFeeFreeAllowancesConfigInput
+ {
+ Symbols = { USDT }
+ });
+ config = TokenContractImplStub.GetTransactionFeeFreeAllowancesConfig.CallAsync(new Empty());
+ config.Result.Value.Count.ShouldBe(1);
+ config.Result.Value.First().Symbol.ShouldBe(NativeTokenSymbol);
+ userAFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserAAddress);
+ userAFreeAllowances.Result.Map.Count.ShouldBe(1);
+ userAFreeAllowances.Result.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+
+ // Duplicate symbols
+ await TokenContractImplStub.RemoveTransactionFeeFreeAllowancesConfig.SendAsync(
+ new RemoveTransactionFeeFreeAllowancesConfigInput
+ {
+ Symbols = { NativeTokenSymbol, NativeTokenSymbol }
+ });
+ config = TokenContractImplStub.GetTransactionFeeFreeAllowancesConfig.CallAsync(new Empty());
+ config.Result.Value.Count.ShouldBe(0);
+ userAFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserAAddress);
+ userAFreeAllowances.Result.Map.Count.ShouldBe(0);
+ }
+
+ [Fact]
+ public async Task RemoveTransactionFeeFreeAllowancesConfig_MultipleTokens_AtOnce_Test()
+ {
+ await ConfigTransactionFeeFreeAllowances_MultipleTokens_AtOnce_Test();
+ await IssueTokenToUserAsync(USDT, 1_000000, UserAAddress);
+
+ var userAFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserAAddress);
+ userAFreeAllowances.Result.Map.Count.ShouldBe(2);
+ var config = TokenContractImplStub.GetTransactionFeeFreeAllowancesConfig.CallAsync(new Empty());
+ config.Result.Value.Count.ShouldBe(2);
+
+ await TokenContractImplStub.RemoveTransactionFeeFreeAllowancesConfig.SendAsync(
+ new RemoveTransactionFeeFreeAllowancesConfigInput
+ {
+ Symbols = { NativeTokenSymbol, USDT }
+ });
+ userAFreeAllowances = TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(UserAAddress);
+ userAFreeAllowances.Result.Map.Count.ShouldBe(0);
+ }
+
+ [Fact]
+ public async Task RemoveTransactionFeeFreeAllowancesConfig_InvalidInput_Test()
+ {
+ var message = await TokenContractImplStub.RemoveTransactionFeeFreeAllowancesConfig.SendWithExceptionAsync(
+ new RemoveTransactionFeeFreeAllowancesConfigInput
+ {
+ Symbols = { USDT }
+ });
+ message.TransactionResult.Error.ShouldContain("Method fee free allowances config not set");
+
+ await ConfigTransactionFeeFreeAllowances_MultipleTokens_AtOnce_Test();
+ message = await TokenContractImplStub.RemoveTransactionFeeFreeAllowancesConfig.SendWithExceptionAsync(
+ new RemoveTransactionFeeFreeAllowancesConfigInput());
+ message.TransactionResult.Error.ShouldContain("Invalid input");
+ }
+
+ [Theory]
+ [InlineData(1000, 0, 1000, 0, 100, 0, 0, 0, 800, 0, 1000, 200)]
+ [InlineData(1000, 0, 100, 0, 100, 0, 0, 0, 0, 0, 900, 200)]
+ [InlineData(1000, 1000, 500, 10, 100, 500, 20, 100, 300, 500, 1000, 200)]
+ [InlineData(1000, 1000, 150, 10, 100, 150, 20, 100, 0, 100, 1000, 200)]
+ public async Task ChargeTransactionFee_Test(long initialELFBalance, long initialUSDTBalance,
+ long freeAmountELF, long refreshSecondsELF, long thresholdELF, long freeAmountUSDT, long refreshSecondsUSDT,
+ long thresholdUSDT, long newFreeAmountELF, long newFreeAmountUSDT, long afterBalance, long basicFee)
+ {
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAsync(DefaultSender, USDT);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialELFBalance);
+ await IssueTokenToDefaultSenderAsync(USDT, initialUSDTBalance);
+
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = freeAmountELF
+ }
+ }
+ },
+ RefreshSeconds = refreshSecondsELF,
+ Threshold = thresholdELF
+ },
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = USDT,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = freeAmountUSDT
+ }
+ }
+ },
+ RefreshSeconds = refreshSecondsUSDT,
+ Threshold = thresholdUSDT
+ }
+ }
+ });
+
+ var methodFee = new MethodFees
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ Fees =
+ {
+ new MethodFee
+ {
+ Symbol = NativeTokenSymbol,
+ BasicFee = basicFee
+ }
+ }
+ };
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
+
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(freeAmountELF);
+ freeAllowances.Map.Keys.Last().ShouldBe(USDT);
+ freeAllowances.Map.Values.Last().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.Last().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.Last().Map.Values.First().Amount.ShouldBe(freeAmountUSDT);
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress
+ };
+
+ var chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRet.Output.Success.ShouldBe(true);
+
+ freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(newFreeAmountELF);
+ freeAllowances.Map.Keys.Last().ShouldBe(USDT);
+ freeAllowances.Map.Values.Last().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.Last().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.Last().Map.Values.First().Amount.ShouldBe(newFreeAmountUSDT);
+
+ await CheckDefaultSenderTokenAsync(NativeTokenSymbol, afterBalance);
+ }
+
+ [Theory]
+ // case 21
+ [InlineData(1000, 1000, 1000, 1000, 1000, 10, 100, 1000, 20, 100, 700, 500, 1000, 1000, 1000, 1000, 300, 500)]
+ // case 22
+ [InlineData(1000, 1000, 1000, 1000, 100, 10, 100, 1000, 20, 100, 0, 500, 100, 1000, 1000, 1000, 1000, 500)]
+ // case 25
+ [InlineData(1000, 100, 1000, 1000, 1000, 10, 10000, 1000, 20, 100, 1000, 500, 0, 1000, 1000, 100, 1000, 500)]
+ public async Task ChargeTransactionFee_MultipleTokens_Test(long initialELFBalance, long initialUSDTBalance,
+ long initialToken1Balance, long initialToken2Balance, long freeAmountELF, long refreshSecondsELF,
+ long thresholdELF, long freeAmountUSDT, long refreshSecondsUSDT, long thresholdUSDT, long newFreeAmountELF,
+ long newFreeAmountUSDT, long afterToken1Balance, long afterToken2Balance, long afterELFBalance,
+ long afterUSDTBalance, long sizeFee, long basicFee)
+ {
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAsync(DefaultSender, USDT);
+
+ await CreateTokenAsync(DefaultSender, Token1);
+ await CreateTokenAsync(DefaultSender, Token2);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialELFBalance);
+ await IssueTokenToDefaultSenderAsync(USDT, initialUSDTBalance);
+ await IssueTokenToDefaultSenderAsync(Token1, initialToken1Balance);
+ await IssueTokenToDefaultSenderAsync(Token2, initialToken2Balance);
+
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = Token1,
+ Amount = freeAmountELF
+ }
+ }
+ },
+ RefreshSeconds = refreshSecondsELF,
+ Threshold = thresholdELF
+ },
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = USDT,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = Token2,
+ Amount = freeAmountUSDT
+ }
+ }
+ },
+ RefreshSeconds = refreshSecondsUSDT,
+ Threshold = thresholdUSDT
+ }
+ }
+ });
+
+ var methodFee = new MethodFees
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ Fees =
+ {
+ new MethodFee
+ {
+ Symbol = Token2,
+ BasicFee = basicFee
+ }
+ }
+ };
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
+
+ var sizeFeeSymbolList = new SymbolListToPayTxSizeFee
+ {
+ SymbolsToPayTxSizeFee =
+ {
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = Token1,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ },
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = NativeTokenSymbol,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ }
+ }
+ };
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
+
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ if (initialELFBalance >= thresholdELF)
+ {
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(freeAmountELF);
+ }
+
+ if (initialUSDTBalance >= thresholdUSDT)
+ {
+ freeAllowances.Map.Keys.Last().ShouldBe(USDT);
+ freeAllowances.Map.Values.Last().Map.Keys.First().ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Symbol.ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Amount.ShouldBe(freeAmountUSDT);
+ }
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = sizeFee,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+
+ var chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRet.Output.Success.ShouldBe(initialToken1Balance + freeAmountELF >= sizeFee);
+
+
+ freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ if (initialELFBalance >= thresholdELF)
+ {
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(newFreeAmountELF);
+ }
+
+ if (initialUSDTBalance >= thresholdUSDT)
+ {
+ freeAllowances.Map.Keys.Last().ShouldBe(USDT);
+ freeAllowances.Map.Values.Last().Map.Keys.First().ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Symbol.ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Amount.ShouldBe(newFreeAmountUSDT);
+ }
+
+ await CheckDefaultSenderTokenAsync(Token1, afterToken1Balance);
+ await CheckDefaultSenderTokenAsync(Token2, afterToken2Balance);
+ await CheckDefaultSenderTokenAsync(NativeTokenSymbol, afterELFBalance);
+ await CheckDefaultSenderTokenAsync(USDT, afterUSDTBalance);
+ }
+
+ [Theory]
+ [InlineData(1000, 600, 200, 200)]
+ public async Task ChargeTransactionFee_NoFreeAllowance_Test(long initialBalance, long afterBalance, long sizeFee,
+ long basicFee)
+ {
+ await SetPrimaryTokenSymbolAsync();
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialBalance);
+
+ var methodFee = new MethodFees
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ Fees =
+ {
+ new MethodFee
+ {
+ Symbol = NativeTokenSymbol,
+ BasicFee = basicFee
+ }
+ }
+ };
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
+
+ var sizeFeeSymbolList = new SymbolListToPayTxSizeFee
+ {
+ SymbolsToPayTxSizeFee =
+ {
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = NativeTokenSymbol,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ }
+ }
+ };
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = sizeFee,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+
+ var chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRet.Output.Success.ShouldBe(true);
+
+ await CheckDefaultSenderTokenAsync(NativeTokenSymbol, afterBalance);
+ }
+
+ [Theory]
+ [InlineData(1000, 1000, 1000, 2000, 2000, 0, 1000, 1000, 500, 1000, 1000, 1000, 1500)]
+ public async Task ChargeTransactionFee_SingleThreshold_Test(long initialBalance, long initialToken1Balance,
+ long initialToken2Balance, long freeAmountTokenA, long freeAmountTokenB, long refreshSeconds,
+ long threshold, long newFreeAmountTokenA, long newFreeAmountTokenB, long afterToken1Balance,
+ long afterToken2Balance, long sizeFee, long basicFee)
+ {
+ await SetPrimaryTokenSymbolAsync();
+
+ await CreateTokenAsync(DefaultSender, Token1);
+ await CreateTokenAsync(DefaultSender, Token2);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialBalance);
+ await IssueTokenToDefaultSenderAsync(Token1, initialToken1Balance);
+ await IssueTokenToDefaultSenderAsync(Token2, initialToken2Balance);
+
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = Token1,
+ Amount = freeAmountTokenA
+ },
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = Token2,
+ Amount = freeAmountTokenB
+ }
+ }
+ },
+ RefreshSeconds = refreshSeconds,
+ Threshold = threshold
+ }
+ }
+ });
+
+ var methodFee = new MethodFees
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ Fees =
+ {
+ new MethodFee
+ {
+ Symbol = Token2,
+ BasicFee = basicFee
+ }
+ }
+ };
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
+
+ var sizeFeeSymbolList = new SymbolListToPayTxSizeFee
+ {
+ SymbolsToPayTxSizeFee =
+ {
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = Token1,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ },
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = NativeTokenSymbol,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ }
+ }
+ };
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
+
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(freeAmountTokenA);
+
+ freeAllowances.Map.Values.First().Map.Keys.Last().ShouldBe(Token2);
+ freeAllowances.Map.Values.First().Map.Values.Last().Symbol.ShouldBe(Token2);
+ freeAllowances.Map.Values.First().Map.Values.Last().Amount.ShouldBe(freeAmountTokenB);
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = sizeFee,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+
+ var chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRet.Output.Success.ShouldBe(true);
+
+
+ freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(newFreeAmountTokenA);
+
+ freeAllowances.Map.Values.First().Map.Keys.Last().ShouldBe(Token2);
+ freeAllowances.Map.Values.First().Map.Values.Last().Symbol.ShouldBe(Token2);
+ freeAllowances.Map.Values.First().Map.Values.Last().Amount.ShouldBe(newFreeAmountTokenB);
+
+ await CheckDefaultSenderTokenAsync(Token1, afterToken1Balance);
+ await CheckDefaultSenderTokenAsync(NativeTokenSymbol, afterToken2Balance);
+ }
+
+ [Theory]
+ [InlineData(1000, 1000, 1000, 1000, 1000, 10, 100, 1000, 20, 100, 0, 1000, 0, 1000, 3000, 5000)]
+ public async Task ChargeTransactionFee_NotEnough_Test(long initialELFBalance, long initialUSDTBalance,
+ long initialToken1Balance, long initialToken2Balance, long freeAmountELF, long refreshSecondsELF,
+ long thresholdELF, long freeAmountUSDT, long refreshSecondsUSDT, long thresholdUSDT, long newFreeAmountELF,
+ long newFreeAmountUSDT, long afterToken1Balance, long afterToken2Balance, long sizeFee, long basicFee)
+ {
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAsync(DefaultSender, USDT);
+
+ await CreateTokenAsync(DefaultSender, Token1);
+ await CreateTokenAsync(DefaultSender, Token2);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialELFBalance);
+ await IssueTokenToDefaultSenderAsync(USDT, initialUSDTBalance);
+ await IssueTokenToDefaultSenderAsync(Token1, initialToken1Balance);
+ await IssueTokenToDefaultSenderAsync(Token2, initialToken2Balance);
+
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = Token1,
+ Amount = freeAmountELF
+ }
+ }
+ },
+ RefreshSeconds = refreshSecondsELF,
+ Threshold = thresholdELF
+ },
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = USDT,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = Token2,
+ Amount = freeAmountUSDT
+ }
+ }
+ },
+ RefreshSeconds = refreshSecondsUSDT,
+ Threshold = thresholdUSDT
+ }
+ }
+ });
+
+ var methodFee = new MethodFees
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ Fees =
+ {
+ new MethodFee
+ {
+ Symbol = Token1,
+ BasicFee = basicFee
+ }
+ }
+ };
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
+
+ var sizeFeeSymbolList = new SymbolListToPayTxSizeFee
+ {
+ SymbolsToPayTxSizeFee =
+ {
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = Token1,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ },
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = NativeTokenSymbol,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ }
+ }
+ };
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
+
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(freeAmountELF);
+ freeAllowances.Map.Keys.Last().ShouldBe(USDT);
+ freeAllowances.Map.Values.Last().Map.Keys.First().ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Symbol.ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Amount.ShouldBe(freeAmountUSDT);
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = sizeFee,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+
+ var chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRet.Output.Success.ShouldBe(false);
+
+
+ freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+
+ freeAllowances.Map.Keys.Last().ShouldBe(USDT);
+ freeAllowances.Map.Values.Last().Map.Keys.First().ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Symbol.ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Amount.ShouldBe(newFreeAmountUSDT);
+
+ await CheckDefaultSenderTokenAsync(Token1, afterToken1Balance);
+ await CheckDefaultSenderTokenAsync(Token2, afterToken2Balance);
+ }
+
+ [Theory]
+ [InlineData(10000, 500, 50, 10000, 300, 100, 100, 100, 2000, 10000, 7800, 10000)]
+ public async Task ChargeTransactionFee_ClearFreeAllowance_Test(long initialBalance, long freeAmount,
+ long refreshSeconds, long threshold, long firstFreeAmount, long secondFreeAmount, long sizeFee, long basicFee,
+ long transferAmount, long firstBalance, long secondBalance, long thirdBalance)
+ {
+ await SetPrimaryTokenSymbolAsync();
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialBalance);
+
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = freeAmount
+ }
+ }
+ },
+ RefreshSeconds = refreshSeconds,
+ Threshold = threshold
+ }
+ }
+ });
+
+ var methodFee = new MethodFees
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ Fees =
+ {
+ new MethodFee
+ {
+ Symbol = NativeTokenSymbol,
+ BasicFee = basicFee
+ }
+ }
+ };
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
+
+ var sizeFeeSymbolList = new SymbolListToPayTxSizeFee
+ {
+ SymbolsToPayTxSizeFee =
+ {
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = NativeTokenSymbol,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ }
+ }
+ };
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
+
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(freeAmount);
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = sizeFee,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+
+ var chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRet.Output.Success.ShouldBe(true);
+
+ freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(firstFreeAmount);
+
+ await CheckDefaultSenderTokenAsync(NativeTokenSymbol, firstBalance);
+
+ await TokenContractStub.Transfer.SendAsync(new TransferInput
+ {
+ Amount = transferAmount,
+ Symbol = NativeTokenSymbol,
+ To = UserCAddress,
+ Memo = "test"
+ });
+
+ chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRet.Output.Success.ShouldBe(true);
+
+ await CheckDefaultSenderTokenAsync(NativeTokenSymbol, secondBalance);
+
+ freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ freeAllowances.Map.ShouldBeEmpty();
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, transferAmount + sizeFee + basicFee);
+
+ chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRet.Output.Success.ShouldBe(true);
+
+ await CheckDefaultSenderTokenAsync(NativeTokenSymbol, thirdBalance);
+
+ freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(secondFreeAmount);
+ }
+
+ [Fact]
+ public async Task ChargeTransactionFee_RefreshTime_Test()
+ {
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAsync(DefaultSender, USDT);
+
+ await CreateTokenAsync(DefaultSender, Token1);
+ await CreateTokenAsync(DefaultSender, Token2);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, 10000);
+ await IssueTokenToDefaultSenderAsync(USDT, 10000);
+ await IssueTokenToDefaultSenderAsync(Token1, 10000);
+ await IssueTokenToDefaultSenderAsync(Token2, 10000);
+
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = Token1,
+ Amount = 1000
+ }
+ }
+ },
+ RefreshSeconds = 20,
+ Threshold = 100
+ },
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = USDT,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = Token2,
+ Amount = 1000
+ }
+ }
+ },
+ RefreshSeconds = 10,
+ Threshold = 100
+ }
+ }
+ });
+
+ var methodFee = new MethodFees
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ Fees =
+ {
+ new MethodFee
+ {
+ Symbol = Token2,
+ BasicFee = 500
+ }
+ }
+ };
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
+
+ var sizeFeeSymbolList = new SymbolListToPayTxSizeFee
+ {
+ SymbolsToPayTxSizeFee =
+ {
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = Token1,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ },
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = NativeTokenSymbol,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ }
+ }
+ };
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
+
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(1000);
+
+ freeAllowances.Map.Keys.Last().ShouldBe(USDT);
+ freeAllowances.Map.Values.Last().Map.Keys.First().ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Symbol.ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Amount.ShouldBe(1000);
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = 1000
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+
+ var chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRet.Output.Success.ShouldBe(true);
+
+ freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(0);
+
+ freeAllowances.Map.Keys.Last().ShouldBe(USDT);
+ freeAllowances.Map.Values.Last().Map.Keys.First().ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Symbol.ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Amount.ShouldBe(500);
+
+ await CheckDefaultSenderTokenAsync(NativeTokenSymbol, 10000);
+ await CheckDefaultSenderTokenAsync(USDT, 10000);
+ await CheckDefaultSenderTokenAsync(Token1, 10000);
+ await CheckDefaultSenderTokenAsync(Token2, 10000);
+
+ chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRet.Output.Success.ShouldBe(true);
+
+ freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(0);
+
+ freeAllowances.Map.Keys.Last().ShouldBe(USDT);
+ freeAllowances.Map.Values.Last().Map.Keys.First().ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Symbol.ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Amount.ShouldBe(0);
+
+ await CheckDefaultSenderTokenAsync(NativeTokenSymbol, 10000);
+ await CheckDefaultSenderTokenAsync(USDT, 10000);
+ await CheckDefaultSenderTokenAsync(Token1, 9000);
+ await CheckDefaultSenderTokenAsync(Token2, 10000);
+
+ BlockTimeProvider.SetBlockTime(TimestampHelper.GetUtcNow().AddSeconds(10));
+
+ chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRet.Output.Success.ShouldBe(true);
+
+ freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(0);
+
+ freeAllowances.Map.Keys.Last().ShouldBe(USDT);
+ freeAllowances.Map.Values.Last().Map.Keys.First().ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Symbol.ShouldBe(Token2);
+ freeAllowances.Map.Values.Last().Map.Values.First().Amount.ShouldBe(500);
+
+ await CheckDefaultSenderTokenAsync(NativeTokenSymbol, 10000);
+ await CheckDefaultSenderTokenAsync(USDT, 10000);
+ await CheckDefaultSenderTokenAsync(Token1, 8000);
+ await CheckDefaultSenderTokenAsync(Token2, 10000);
+ }
+
+ [Theory]
+ [InlineData(1000, 1000, 1000, 0, 10, 800, 1000, 1000, 100, 100)]
+ public async Task ChargeTransactionFee_FreeAllowanceFirst_Test(long initialBalance, long initialToken1Balance,
+ long freeAmount, long refreshSeconds, long threshold, long newFreeAmount, long afterToken1Balance,
+ long afterELFBalance, long sizeFee, long basicFee)
+ {
+ await SetPrimaryTokenSymbolAsync();
+
+ await CreateTokenAsync(DefaultSender, Token1);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialBalance);
+ await IssueTokenToDefaultSenderAsync(Token1, initialToken1Balance);
+
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = Token1,
+ Amount = freeAmount
+ }
+ }
+ },
+ RefreshSeconds = refreshSeconds,
+ Threshold = threshold
+ }
+ }
+ });
+
+ var methodFee = new MethodFees
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ Fees =
+ {
+ new MethodFee
+ {
+ Symbol = NativeTokenSymbol,
+ BasicFee = basicFee
+ },
+ new MethodFee
+ {
+ Symbol = Token1,
+ BasicFee = basicFee
+ }
+ }
+ };
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
+
+ var sizeFeeSymbolList = new SymbolListToPayTxSizeFee
+ {
+ SymbolsToPayTxSizeFee =
+ {
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = NativeTokenSymbol,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ },
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = Token1,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ }
+ }
+ };
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
+
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(freeAmount);
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = sizeFee,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+
+ var chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRet.Output.Success.ShouldBe(true);
+
+ freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(newFreeAmount);
+
+ await CheckDefaultSenderTokenAsync(Token1, afterToken1Balance);
+ await CheckDefaultSenderTokenAsync(NativeTokenSymbol, afterELFBalance);
+ }
+
+ [Theory]
+ // case 24
+ [InlineData(1000, 1000, 1000, 1000, Token1, 1000, Token1, 1000, 600, 10, Token2, 1000, Token2, 1000, 300, 10, 1000,
+ 1000, 1000, 1000, 0, 0, 1000, 1000, 5000, 1, 1, USDT, 3000, Token2, 3000, false)]
+ // case 28
+ [InlineData(10000, 10000, 1000, 0, Token1, 2000, NativeTokenSymbol, 2000, 600, 10000, Token1, 1000, USDT, 200, 300,
+ 10000, 2000, 0, 0, 200, 10000, 10000, 1000, 0, 2000, 1, 2, Token1, 1000, USDT, 200, true)]
+ // case 29
+ [InlineData(10000, 10000, 1000, 0, Token1, 2000, NativeTokenSymbol, 1000, 600, 10000, Token1, 1000, USDT, 100, 300,
+ 10000, 1000, 1000, 0, 100, 10000, 10000, 1000, 0, 2000, 1, 2, Token1, 1000, USDT, 200, true)]
+ // case 30
+ [InlineData(10000, 10000, 1000, 0, Token1, 1000, NativeTokenSymbol, 1000, 600, 100, Token1, 1000, USDT, 100, 300,
+ 100, 500, 0, 0, 100, 9000, 10000, 1000, 0, 2000, 1, 1, Token1, 1500, USDT, 200, true)]
+ // case 31
+ [InlineData(10000, 10000, 10000, 0, Token1, 1000, NativeTokenSymbol, 1000, 600, 100, Token1, 1000,
+ NativeTokenSymbol, 1000, 300, 100, 0, 0, 0, 0, 9000, 10000, 7000, 0, 3000, 5, 3, NativeTokenSymbol, 3000,
+ Token1, 3000, true)]
+ // case 32
+ [InlineData(10000, 10000, 1000, 0, Token1, 1000, NativeTokenSymbol, 1000, 600, 100, Token1, 1000, NativeTokenSymbol,
+ 1000, 300, 100, 0, 0, 0, 0, 0, 10000, 0, 0, 3000, 5, 3, NativeTokenSymbol, 15000, USDT, 20000, false)]
+ // case 33
+ [InlineData(5000, 10000, 0, 0, Token1, 1000, Token1, 1000, 600, 100, Token2, 1000, Token2, 1000, 300, 100, 0, 0,
+ 1000, 1000, 0, 8000, 0, 0, 10000, 1, 5, USDT, 2000, NativeTokenSymbol, 0, false)]
+ [InlineData(2000, 0, 0, 0, Token1, 0, NativeTokenSymbol, 0, 0, 10000, Token2, 0, Token2, 0, 0, 10000, 0, 0, 0, 0,
+ 500, 0, 0, 0, 0, 1, 1, NativeTokenSymbol, 1500, USDT, 100, true)]
+ public async Task ChargeTransactionFee_MultipleTxFeeTokens_Test(long initialELFBalance, long initialUSDTBalance,
+ long initialToken1Balance, long initialToken2Balance, string firstFreeSymbolELF, long firstFreeAmountELF,
+ string secondFreeSymbolELF, long secondFreeAmountELF, long refreshSecondsELF, long thresholdELF,
+ string firstFreeSymbolUSDT, long firstFreeAmountUSDT, string secondFreeSymbolUSDT, long secondFreeAmountUSDT,
+ long refreshSecondsUSDT, long thresholdUSDT, long newFirstFreeAmountELF, long newSecondFreeAmountELF,
+ long newFirstFreeAmountUSDT, long newSecondFreeAmountUSDT, long afterELFBalance, long afterUSDTBalance,
+ long afterToken1Balance, long afterToken2Balance, long sizeFee, int addedTokenWeight, int baseTokenWeight,
+ string firstBaseFeeSymbol, long firstBaseFeeAmount, string secondBaseFeeSymbol, long secondBaseFeeAmount,
+ bool chargeFeeResult)
+ {
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAsync(DefaultSender, USDT);
+
+ await CreateTokenAsync(DefaultSender, Token1);
+ await CreateTokenAsync(DefaultSender, Token2);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, initialELFBalance);
+ await IssueTokenToDefaultSenderAsync(USDT, initialUSDTBalance);
+ await IssueTokenToDefaultSenderAsync(Token1, initialToken1Balance);
+ await IssueTokenToDefaultSenderAsync(Token2, initialToken2Balance);
+
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = firstFreeSymbolELF,
+ Amount = firstFreeAmountELF
+ },
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = secondFreeSymbolELF,
+ Amount = secondFreeAmountELF
+ }
+ }
+ },
+ RefreshSeconds = refreshSecondsELF,
+ Threshold = thresholdELF
+ },
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = USDT,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = firstFreeSymbolUSDT,
+ Amount = firstFreeAmountUSDT
+ },
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = secondFreeSymbolUSDT,
+ Amount = secondFreeAmountUSDT
+ }
+ }
+ },
+ RefreshSeconds = refreshSecondsUSDT,
+ Threshold = thresholdUSDT
+ }
+ }
+ });
+
+ var methodFee = new MethodFees
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ Fees =
+ {
+ new MethodFee
+ {
+ Symbol = firstBaseFeeSymbol,
+ BasicFee = firstBaseFeeAmount
+ }
+ }
+ };
+
+ if (secondBaseFeeAmount > 0)
+ {
+ methodFee.Fees.Add(new MethodFee
+ {
+ Symbol = secondBaseFeeSymbol,
+ BasicFee = secondBaseFeeAmount
+ });
+ }
+
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
+
+ var sizeFeeSymbolList = new SymbolListToPayTxSizeFee
+ {
+ SymbolsToPayTxSizeFee =
+ {
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = NativeTokenSymbol,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ },
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = Token1,
+ AddedTokenWeight = addedTokenWeight,
+ BaseTokenWeight = baseTokenWeight
+ }
+ }
+ };
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
+
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ if (initialELFBalance >= thresholdELF)
+ {
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(firstFreeSymbolELF);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(firstFreeSymbolELF);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(firstFreeAmountELF);
+
+ freeAllowances.Map.Values.First().Map.Keys.Last().ShouldBe(secondFreeSymbolELF);
+ freeAllowances.Map.Values.First().Map.Values.Last().Symbol.ShouldBe(secondFreeSymbolELF);
+ freeAllowances.Map.Values.First().Map.Values.Last().Amount.ShouldBe(secondFreeAmountELF);
+ }
+
+ if (initialUSDTBalance >= thresholdUSDT)
+ {
+ freeAllowances.Map.Keys.Last().ShouldBe(USDT);
+ freeAllowances.Map.Values.Last().Map.Keys.First().ShouldBe(firstFreeSymbolUSDT);
+ freeAllowances.Map.Values.Last().Map.Values.First().Symbol.ShouldBe(firstFreeSymbolUSDT);
+ freeAllowances.Map.Values.Last().Map.Values.First().Amount.ShouldBe(firstFreeAmountUSDT);
+
+ freeAllowances.Map.Values.Last().Map.Keys.Last().ShouldBe(secondFreeSymbolUSDT);
+ freeAllowances.Map.Values.Last().Map.Values.Last().Symbol.ShouldBe(secondFreeSymbolUSDT);
+ freeAllowances.Map.Values.Last().Map.Values.Last().Amount.ShouldBe(secondFreeAmountUSDT);
+ }
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = sizeFee,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+
+ var chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRet.Output.Success.ShouldBe(chargeFeeResult);
+
+ freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DefaultSender);
+ if (afterELFBalance >= thresholdELF)
+ {
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(firstFreeSymbolELF);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(firstFreeSymbolELF);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(newFirstFreeAmountELF);
+
+ freeAllowances.Map.Values.First().Map.Keys.Last().ShouldBe(secondFreeSymbolELF);
+ freeAllowances.Map.Values.First().Map.Values.Last().Symbol.ShouldBe(secondFreeSymbolELF);
+ freeAllowances.Map.Values.First().Map.Values.Last().Amount.ShouldBe(newSecondFreeAmountELF);
+ }
+
+ if (afterUSDTBalance >= thresholdUSDT)
+ {
+ freeAllowances.Map.Keys.Last().ShouldBe(USDT);
+ freeAllowances.Map.Values.Last().Map.Keys.First().ShouldBe(firstFreeSymbolUSDT);
+ freeAllowances.Map.Values.Last().Map.Values.First().Symbol.ShouldBe(firstFreeSymbolUSDT);
+ freeAllowances.Map.Values.Last().Map.Values.First().Amount.ShouldBe(newFirstFreeAmountUSDT);
+
+ freeAllowances.Map.Values.Last().Map.Keys.Last().ShouldBe(secondFreeSymbolUSDT);
+ freeAllowances.Map.Values.Last().Map.Values.Last().Symbol.ShouldBe(secondFreeSymbolUSDT);
+ freeAllowances.Map.Values.Last().Map.Values.Last().Amount.ShouldBe(newSecondFreeAmountUSDT);
+ }
+
+ await CheckDefaultSenderTokenAsync(Token1, afterToken1Balance);
+ await CheckDefaultSenderTokenAsync(Token2, afterToken2Balance);
+ await CheckDefaultSenderTokenAsync(NativeTokenSymbol, afterELFBalance);
+ await CheckDefaultSenderTokenAsync(USDT, afterUSDTBalance);
+ }
+
+ [Theory]
+ [InlineData(100, 100, 100)]
+ public async Task ChargeTransactionFee_DelegateMultipleFeeTokens_PriorityAllowance_Success_Test(
+ long initialELFBalance, long initialUSDTBalance,
+ long initialToken1Balance)
+ {
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAsync(DefaultSender, USDT);
+ await CreateTokenAsync(DefaultSender, Token1);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, 5);
+ await IssueTokenToDefaultSenderAsync(USDT, 5);
+ await IssueTokenToDefaultSenderAsync(Token1, 5);
+ await IssueTokenToUserAsync(NativeTokenSymbol, initialELFBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(USDT, initialUSDTBalance, DelegateeAddress);
+ await IssueTokenToUserAsync(Token1, initialToken1Balance, DelegateeAddress);
+
+ await SetDelegateeAsync();
+
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ Amount = 5
+ },
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = USDT,
+ Amount = 30
+ },
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = Token1,
+ Amount = 10
+ }
+ }
+ },
+ RefreshSeconds = 600,
+ Threshold = 100
+ }
+ }
+ });
+ var methodFee = new MethodFees
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ Fees =
+ {
+ new MethodFee
+ {
+ Symbol = NativeTokenSymbol,
+ BasicFee = 6
+ },
+ new MethodFee
+ {
+ Symbol = Token1,
+ BasicFee = 7
+ }
+ }
+ };
+
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
+
+ var sizeFeeSymbolList = new SymbolListToPayTxSizeFee
+ {
+ SymbolsToPayTxSizeFee =
+ {
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = NativeTokenSymbol,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ },
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = USDT,
+ AddedTokenWeight = 3,
+ BaseTokenWeight = 1
+ }
+ }
+ };
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
+
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DelegateeAddress);
+ if (initialELFBalance >= 100)
+ {
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(5);
+
+ freeAllowances.Map.Values.First().Map.Keys.ElementAt(1).ShouldBe(USDT);
+ freeAllowances.Map.Values.First().Map.Values.ElementAt(1).Symbol.ShouldBe(USDT);
+ freeAllowances.Map.Values.First().Map.Values.ElementAt(1).Amount.ShouldBe(30);
+
+ freeAllowances.Map.Values.First().Map.Keys.Last().ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.Last().Symbol.ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.Last().Amount.ShouldBe(10);
+ }
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = 7,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+
+ var chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRet.Output.Success.ShouldBe(true);
+
+ freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DelegateeAddress);
+ var balance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Owner = DelegateeAddress,
+ Symbol = NativeTokenSymbol
+ });
+ if (balance.Balance >= 100)
+ {
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(NativeTokenSymbol);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(5);
+
+ freeAllowances.Map.Values.First().Map.Keys.ElementAt(1).ShouldBe(USDT);
+ freeAllowances.Map.Values.First().Map.Values.ElementAt(1).Symbol.ShouldBe(USDT);
+ freeAllowances.Map.Values.First().Map.Values.ElementAt(1).Amount.ShouldBe(9);
+
+ freeAllowances.Map.Values.First().Map.Keys.Last().ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.Last().Symbol.ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.Last().Amount.ShouldBe(3);
+ }
+
+ await CheckUserTokenAsync(DelegateeAddress, Token1, 100);
+ await CheckUserTokenAsync(DelegateeAddress, NativeTokenSymbol, 100);
+ await CheckUserTokenAsync(DelegateeAddress, USDT, 100);
+ }
+
+ [Fact]
+ public async Task ChargeTransactionFee_DelegateMultipleFeeTokens_PriorityAllowanceGreaterThan0_Success_Test()
+ {
+ await SetPrimaryTokenSymbolAsync();
+ await CreateTokenAsync(DefaultSender, USDT);
+ await CreateTokenAsync(DefaultSender, Token1);
+
+ await IssueTokenToDefaultSenderAsync(NativeTokenSymbol, 5);
+ await IssueTokenToDefaultSenderAsync(USDT, 5);
+ await IssueTokenToDefaultSenderAsync(Token1, 5);
+ await IssueTokenToUserAsync(NativeTokenSymbol, 100, DelegateeAddress);
+ await IssueTokenToUserAsync(USDT, 100, DelegateeAddress);
+ await IssueTokenToUserAsync(Token1, 100, DelegateeAddress);
+
+ await SetDelegateeAsync();
+
+ await TokenContractImplStub.ConfigTransactionFeeFreeAllowances.SendAsync(
+ new ConfigTransactionFeeFreeAllowancesInput
+ {
+ Value =
+ {
+ new ConfigTransactionFeeFreeAllowance
+ {
+ Symbol = NativeTokenSymbol,
+ TransactionFeeFreeAllowances = new TransactionFeeFreeAllowances
+ {
+ Value =
+ {
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = USDT,
+ Amount = 10
+ },
+ new TransactionFeeFreeAllowance
+ {
+ Symbol = Token1,
+ Amount = 10
+ }
+ }
+ },
+ RefreshSeconds = 600,
+ Threshold = 100
+ }
+ }
+ });
+ var methodFee = new MethodFees
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ Fees =
+ {
+ new MethodFee
+ {
+ Symbol = NativeTokenSymbol,
+ BasicFee = 10
+ },
+ new MethodFee
+ {
+ Symbol = Token1,
+ BasicFee = 30
+ }
+ }
+ };
+
+ await TokenContractImplStub.SetMethodFee.SendAsync(methodFee);
+
+ var sizeFeeSymbolList = new SymbolListToPayTxSizeFee
+ {
+ SymbolsToPayTxSizeFee =
+ {
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = NativeTokenSymbol,
+ AddedTokenWeight = 1,
+ BaseTokenWeight = 1
+ },
+ new SymbolToPayTxSizeFee
+ {
+ TokenSymbol = USDT,
+ AddedTokenWeight = 3,
+ BaseTokenWeight = 1
+ }
+ }
+ };
+ await TokenContractImplStub.SetSymbolsToPayTxSizeFee.SendAsync(sizeFeeSymbolList);
+ var initialELFBalance = (await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Owner = DelegateeAddress,
+ Symbol = NativeTokenSymbol
+ })).Balance;
+ var freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DelegateeAddress);
+ if (initialELFBalance >= 100)
+ {
+ freeAllowances.Map.Keys.First().ShouldBe(NativeTokenSymbol);
+
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(USDT);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(USDT);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(10);
+
+ freeAllowances.Map.Values.First().Map.Keys.Last().ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.Last().Symbol.ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.Last().Amount.ShouldBe(10);
+ }
+
+ var chargeTransactionFeesInput = new ChargeTransactionFeesInput
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ TransactionSizeFee = 7,
+ };
+ chargeTransactionFeesInput.SymbolsToPayTxSizeFee.AddRange(sizeFeeSymbolList.SymbolsToPayTxSizeFee);
+
+ var chargeFeeRet = await TokenContractStub.ChargeTransactionFees.SendAsync(chargeTransactionFeesInput);
+ chargeFeeRet.Output.Success.ShouldBe(true);
+
+ freeAllowances = await TokenContractImplStub.GetTransactionFeeFreeAllowances.CallAsync(DelegateeAddress);
+ var balance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Owner = DelegateeAddress,
+ Symbol = NativeTokenSymbol
+ });
+ if (balance.Balance >= 100)
+ {
+ freeAllowances.Map.Values.First().Map.Keys.First().ShouldBe(USDT);
+ freeAllowances.Map.Values.First().Map.Values.First().Symbol.ShouldBe(USDT);
+ freeAllowances.Map.Values.First().Map.Values.First().Amount.ShouldBe(0);
+
+ freeAllowances.Map.Values.First().Map.Keys.Last().ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.Last().Symbol.ShouldBe(Token1);
+ freeAllowances.Map.Values.First().Map.Values.Last().Amount.ShouldBe(0);
+ }
+
+ await CheckUserTokenAsync(DelegateeAddress, Token1, 80);
+ await CheckUserTokenAsync(DelegateeAddress, NativeTokenSymbol, 100);
+ await CheckUserTokenAsync(DelegateeAddress, USDT, 89);
+ }
+
+ private async Task SetDelegateeAsync()
+ {
+ var delegations = new Dictionary
+ {
+ [NativeTokenSymbol] = 100,
+ [USDT] = 100,
+ [Token1] = 100
+ };
+ var delegateInfo1 = new DelegateInfo
+ {
+ Delegations = { delegations },
+ IsUnlimitedDelegate = false,
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ ContractAddress = TokenContractAddress,
+ };
+ await TokenContractStubDelegate1.SetTransactionFeeDelegateInfos.SendAsync(
+ new SetTransactionFeeDelegateInfosInput
+ {
+ DelegatorAddress = DefaultSender,
+ DelegateInfoList = { delegateInfo1 }
+ });
+ }
+
+ private async Task CheckDefaultSenderTokenAsync(string symbol, long amount)
+ {
+ var balance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Owner = DefaultSender,
+ Symbol = symbol
+ });
+
+ balance.Balance.ShouldBe(amount);
+ }
+
+ private async Task CheckUserTokenAsync(Address user, string symbol, long amount)
+ {
+ var balance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Owner = user,
+ Symbol = symbol
+ });
+
+ balance.Balance.ShouldBe(amount);
+ }
+
+ private async Task CreateTokenAndIssueAsync()
+ {
+ await CreateTokenAsync(DefaultSender, USDT);
+ await IssueTokenToUserAsync(NativeTokenSymbol, 1_00000000, UserAAddress);
+ await IssueTokenToUserAsync(USDT, 1_000000, UserBAddress);
+ await IssueTokenToUserAsync(NativeTokenSymbol, 1_00000000, UserCAddress);
+ await IssueTokenToUserAsync(USDT, 1_000000, UserCAddress);
+ }
+}
\ No newline at end of file
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTest.cs b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTest.cs
index 006c7697dd..b265f1cca9 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTest.cs
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTest.cs
@@ -61,7 +61,8 @@ await tokenStub.Create.SendAsync(new CreateInput
IsBurnable = true,
TokenName = "test token",
TotalSupply = 1_000_000_00000000L,
- Issuer = DefaultSender
+ Issuer = DefaultSender,
+ Owner = DefaultSender
});
if (issueAmount != 0)
@@ -339,7 +340,7 @@ await tokenContractStub.Transfer.SendAsync(new TransferInput
[InlineData(9, 0, 1, 10, 1, 2, "ELF", 9, false)]
[InlineData(100000000, 2, 2, 0, 1, 2, "TSA", 1, true)]
[InlineData(100000000, 2, 2, 0, 13, 2, "TSB", 2, true)]
- [InlineData(100000000, 2, 2, 0, 20, 20, "TSB", 2, false)]
+ [InlineData(100000000, 2, 2, 0, 20, 20, "TSA", 2, false)]
[InlineData(1, 0, 1, 0, 1, 2, "TSB", 1, false)]
[InlineData(10, 0, 0, 0, 1, 2, "ELF", 10, false)] // Charge 10 ELFs tx size fee.
public async Task ChargeFee_Set_Method_Fees_Tests(long balance1, long balance2, long balance3, long fee1, long fee2,
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTestBase.cs b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTestBase.cs
index 33fff08c64..62376dcaec 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTestBase.cs
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTestBase.cs
@@ -10,7 +10,6 @@
using AElf.Cryptography.ECDSA;
using AElf.CSharp.Core.Extension;
using AElf.Kernel.Blockchain.Application;
-using AElf.Kernel.Blockchain.Domain;
using AElf.Kernel.Configuration;
using AElf.Kernel.Proposal;
using AElf.Kernel.SmartContract.Application;
@@ -23,18 +22,55 @@
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Threading;
-using Xunit;
namespace AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests;
public class ExecutionPluginForMethodFeeTestBase : ContractTestBase
{
+ internal Address ParliamentAddress;
+ internal ParliamentContractImplContainer.ParliamentContractImplStub ParliamentContractStub;
+ protected ECKeyPair DefaultSenderKeyPair => Accounts[0].KeyPair;
+ protected Address DefaultAddress => Accounts[0].Address;
+
+ protected ExecutionPluginForMethodFeeTestBase()
+ {
+ AsyncHelper.RunSync(InitializeContracts);
+ }
+
+ private async Task InitializeContracts()
+ {
+ await DeployContractsAsync();
+ await InitializedParliament();
+ }
+
+ private async Task DeployContractsAsync()
+ {
+ const int category = KernelConstants.CodeCoverageRunnerCategory;
+ // Parliament
+ {
+ var code = Codes.Single(kv => kv.Key.Contains("MockParliament")).Value;
+ ParliamentAddress = await DeploySystemSmartContract(category, code,
+ ParliamentSmartContractAddressNameProvider.Name, DefaultSenderKeyPair);
+ ParliamentContractStub =
+ GetTester(ParliamentAddress,
+ DefaultSenderKeyPair);
+ }
+ }
+
+ private async Task InitializedParliament()
+ {
+ await ParliamentContractStub.Initialize.SendAsync(new InitializeInput
+ {
+ ProposerAuthorityRequired = false,
+ PrivilegedProposer = DefaultAddress
+ });
+ }
}
public class ExecutionPluginForUserContractMethodFeeTestBase : ContractTestBase
{
protected const string NativeTokenSymbol = "ELF";
-
+
internal Address ConfigurationAddress;
internal Address ParliamentAddress;
internal Address ConsensusContractAddress;
@@ -46,12 +82,13 @@ public class ExecutionPluginForUserContractMethodFeeTestBase : ContractTestBase<
internal AEDPoSContractContainer.AEDPoSContractStub AEDPoSContractStub { get; set; }
protected new ISmartContractAddressService ContractAddressService =>
Application.ServiceProvider.GetRequiredService();
+
protected IBlockchainService BlockChainService =>
Application.ServiceProvider.GetRequiredService();
-
+
protected ECKeyPair DefaultSenderKeyPair => Accounts[0].KeyPair;
protected Address DefaultAddress => Accounts[0].Address;
-
+
protected List InitialCoreDataCenterKeyPairs =>
Accounts.Take(1).Select(a => a.KeyPair).ToList();
@@ -59,17 +96,19 @@ protected ExecutionPluginForUserContractMethodFeeTestBase()
{
AsyncHelper.RunSync(InitializeContracts);
}
+
private async Task InitializeContracts()
{
await DeployContractsAsync();
- AuthorizationContractStub=
+ AuthorizationContractStub =
GetTester(ParliamentAddress,
DefaultSenderKeyPair);
await InitializeAElfConsensus();
- await InitializedParliament();
+ await InitializedParliament();
TokenContractStub = await GetTokenContractStubAsync();
await SetPrimaryTokenSymbolAsync();
}
+
private async Task GetTokenContractAddressAsync()
{
var preBlockHeader = await BlockChainService.GetBestChainLastBlockHeaderAsync();
@@ -83,6 +122,7 @@ private async Task GetTokenContractAddressAsync()
return contractMapping[TokenSmartContractAddressNameProvider.Name];
}
+
private async Task GetTokenContractStubAsync()
{
TokenContractAddress = await GetTokenContractAddressAsync();
@@ -115,13 +155,12 @@ private async Task DeployContractsAsync()
}
// Parliament
{
- var code = Codes.Single(kv => kv.Key.Contains("Parliament")).Value;
+ var code = Codes.Single(kv => kv.Key.Contains("MockParliament")).Value;
ParliamentAddress = await DeploySystemSmartContract(category, code,
ParliamentSmartContractAddressNameProvider.Name, DefaultSenderKeyPair);
ParliamentContractStub =
GetTester(ParliamentAddress,
DefaultSenderKeyPair);
-
}
//Consensus
{
@@ -133,6 +172,7 @@ private async Task DeployContractsAsync()
DefaultSenderKeyPair);
}
}
+
private async Task InitializeAElfConsensus()
{
{
@@ -180,6 +220,7 @@ private Round GenerateFirstRoundOfNewTerm(MinerList minerList, int miningInterva
return round;
}
+
private async Task SetPrimaryTokenSymbolAsync()
{
await TokenContractStub.SetPrimaryTokenSymbol.SendAsync(new SetPrimaryTokenSymbolInput
@@ -283,9 +324,15 @@ public class ExecutePluginTransactionDirectlyForMethodFeeTestBase : ContractTest
ExecutionPluginTransactionDirectlyForMethodFeeTestModule>
{
protected const string NativeTokenSymbol = "ELF";
+ protected const string USDT = "USDT";
+ protected const string Token1 = "TOKENA";
+ protected const string Token2 = "TOKENB";
+
+ protected readonly IBlockTimeProvider BlockTimeProvider;
protected ExecutePluginTransactionDirectlyForMethodFeeTestBase()
{
+ BlockTimeProvider = GetRequiredService();
AsyncHelper.RunSync(InitializeContracts);
}
@@ -293,29 +340,75 @@ protected ExecutePluginTransactionDirectlyForMethodFeeTestBase()
internal Address TreasuryContractAddress { get; set; }
internal Address ConsensusContractAddress { get; set; }
internal TokenContractContainer.TokenContractStub TokenContractStub { get; set; }
+ internal TokenContractImplContainer.TokenContractImplStub TokenContractImplStub { get; set; }
+ internal TokenContractImplContainer.TokenContractImplStub TokenContractImplStub2 { get; set; }
internal TokenContractContainer.TokenContractStub TokenContractStub2 { get; set; }
internal TokenContractContainer.TokenContractStub TokenContractStub3 { get; set; }
+ internal TokenContractContainer.TokenContractStub TokenContractStubDelegator { get; set; }
+
+ internal TokenContractImplContainer.TokenContractImplStub TokenContractStubDelegate1 { get; set; }
+ internal TokenContractImplContainer.TokenContractImplStub TokenContractStubDelegate2 { get; set; }
+ internal TokenContractImplContainer.TokenContractImplStub TokenContractStubDelegate3 { get; set; }
+ internal TokenContractImplContainer.TokenContractImplStub TokenContractStubSecondaryDelegate1 { get; set; }
+ internal TokenContractImplContainer.TokenContractImplStub TokenContractStubSecondaryDelegate2 { get; set; }
+
+ internal TokenContractImplContainer.TokenContractImplStub TokenContractStubSecondaryDelegate3 { get; set; }
+ internal TokenContractImplContainer.TokenContractImplStub TokenContractStubSecondaryDelegate4 { get; set; }
+ internal TokenContractImplContainer.TokenContractImplStub TokenContractStubSecondaryDelegate5 { get; set; }
+ internal TokenContractImplContainer.TokenContractImplStub TokenContractStubSecondaryDelegate6 { get; set; }
+
internal ParliamentContractImplContainer.ParliamentContractImplStub ParliamentContractStub { get; set; }
internal AEDPoSContractContainer.AEDPoSContractStub AEDPoSContractStub { get; set; }
internal ECKeyPair DefaultSenderKeyPair => Accounts[0].KeyPair;
internal ECKeyPair DelegateeKeyPair => Accounts[1].KeyPair;
+ internal ECKeyPair Delegatee2KeyPair => Accounts[3].KeyPair;
+ internal ECKeyPair Delegatee3KeyPair => Accounts[5].KeyPair;
+ internal ECKeyPair SecondaryDelegatee1KeyPair => Accounts[6].KeyPair;
+ internal ECKeyPair SecondaryDelegatee2KeyPair => Accounts[7].KeyPair;
+
+ internal ECKeyPair SecondaryDelegatee3KeyPair => Accounts[8].KeyPair;
+
+ internal ECKeyPair SecondaryDelegatee4KeyPair => Accounts[9].KeyPair;
+
+ internal ECKeyPair SecondaryDelegatee5KeyPair => Accounts[11].KeyPair;
+
+ internal ECKeyPair SecondaryDelegatee6KeyPair => Accounts[12].KeyPair;
+
+
internal ECKeyPair UserKeyPair => Accounts[2].KeyPair;
internal ECKeyPair UserAKeyPair => Accounts[3].KeyPair;
internal ECKeyPair UserTomSenderKeyPair => Accounts[10].KeyPair;
internal Address UserTomSender => Accounts[10].Address;
+
protected List InitialCoreDataCenterKeyPairs =>
Accounts.Take(1).Select(a => a.KeyPair).ToList();
internal Address DefaultSender => Accounts[0].Address;
- internal Address delegateeAddress => Accounts[1].Address;
+ internal Address DelegateeAddress => Accounts[1].Address;
+ internal Address Delegatee2Address => Accounts[3].Address;
+ internal Address Delegatee3Address => Accounts[5].Address;
+ internal Address SecondaryDelegatee1Address => Accounts[6].Address;
+ internal Address SecondaryDelegatee2Address => Accounts[7].Address;
+
+ internal Address SecondaryDelegatee3Address => Accounts[8].Address;
+
+ internal Address SecondaryDelegatee4Address => Accounts[9].Address;
+
+ internal Address SecondaryDelegatee5Address => Accounts[11].Address;
+
+ internal Address SecondaryDelegatee6Address => Accounts[12].Address;
+
+
+
internal Address userAddress => Accounts[2].Address;
internal TokenContractContainer.TokenContractStub TokenContractStubA { get; set; }
internal Address UserAAddress => Accounts[3].Address;
- internal Address UserCAddress => Accounts[4].Address;
+ internal Address UserBAddress => Accounts[4].Address;
+ internal Address UserCAddress => Accounts[5].Address;
+
-
private async Task InitializeContracts()
{
await DeployContractsAsync();
@@ -345,15 +438,42 @@ private async Task DeployContractsAsync()
GetTester(TokenContractAddress, DefaultSenderKeyPair);
TokenContractStub2 =
GetTester(TokenContractAddress, DelegateeKeyPair);
- TokenContractStub3 =
+ TokenContractStub3 =
GetTester(TokenContractAddress, UserKeyPair);
- TokenContractStubA =
+ TokenContractStubA =
GetTester(TokenContractAddress, UserKeyPair);
+ TokenContractStubDelegator =
+ GetTester(TokenContractAddress, UserTomSenderKeyPair);
+ TokenContractStubDelegate1 =
+ GetTester(TokenContractAddress, DelegateeKeyPair);
+ TokenContractStubDelegate2 =
+ GetTester(TokenContractAddress, Delegatee2KeyPair);
+ TokenContractImplStub =
+ GetTester(TokenContractAddress, DefaultSenderKeyPair);
+ TokenContractStubDelegate3 =
+ GetTester(TokenContractAddress, Delegatee3KeyPair);
+ TokenContractStubSecondaryDelegate1 =
+ GetTester(TokenContractAddress, SecondaryDelegatee1KeyPair);
+ TokenContractStubSecondaryDelegate2 =
+ GetTester(TokenContractAddress, SecondaryDelegatee2KeyPair);
+ TokenContractStubSecondaryDelegate3 =
+ GetTester(TokenContractAddress, SecondaryDelegatee3KeyPair);
+ TokenContractStubSecondaryDelegate4 =
+ GetTester(TokenContractAddress, SecondaryDelegatee4KeyPair);
+ TokenContractStubSecondaryDelegate5 =
+ GetTester(TokenContractAddress, SecondaryDelegatee5KeyPair);
+ TokenContractStubSecondaryDelegate6 =
+ GetTester(TokenContractAddress, SecondaryDelegatee6KeyPair);
+
+ TokenContractImplStub =
+ GetTester(TokenContractAddress, DefaultSenderKeyPair);
+ TokenContractImplStub2 =
+ GetTester(TokenContractAddress, UserKeyPair);
}
// Parliament
{
- var code = Codes.Single(kv => kv.Key.Contains("Parliament")).Value;
+ var code = Codes.Single(kv => kv.Key.Contains("MockParliament")).Value;
var parliamentContractAddress = await DeploySystemSmartContract(category, code,
ParliamentSmartContractAddressNameProvider.Name, DefaultSenderKeyPair);
ParliamentContractStub =
@@ -390,7 +510,8 @@ private async Task CreateNativeTokenAsync()
IsBurnable = true,
TokenName = "elf token",
TotalSupply = totalSupply,
- Issuer = DefaultSender
+ Issuer = DefaultSender,
+ Owner = DefaultSender
});
createResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
}
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTestModule.cs b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTestModule.cs
index b05c11846f..874d7b8049 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTestModule.cs
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTestModule.cs
@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.Threading.Tasks;
-using AElf.Blockchains.MainChain;
using AElf.Contracts.TestBase;
using AElf.ContractTestKit;
using AElf.Cryptography;
@@ -11,7 +10,6 @@
using AElf.Kernel.Miner.Application;
using AElf.Kernel.SmartContract.Application;
using AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests.Service;
-using AElf.Kernel.Token;
using AElf.OS.Node.Application;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
@@ -47,8 +45,8 @@ public override void ConfigureServices(ServiceConfigurationContext context)
[DependsOn(
typeof(ContractTestModule),
-typeof(ExecutionPluginForMethodFeeModule),
-typeof(FeeCalculationModule))]
+ typeof(ExecutionPluginForMethodFeeModule),
+ typeof(FeeCalculationModule))]
public class ExecutionPluginForUserContractMethodFeeTestModule : ContractTestModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
@@ -95,6 +93,7 @@ public class ExecutionPluginTransactionDirectlyForMethodFeeTestModule : Contract
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure(o => o.ContractDeploymentAuthorityRequired = false);
+ context.Services.AddSingleton();
context.Services.RemoveAll();
context.Services.RemoveAll();
context.Services.RemoveAll();
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeWithForkTest.cs b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeWithForkTest.cs
index e6bebf3081..6a6ffe5a73 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeWithForkTest.cs
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeWithForkTest.cs
@@ -33,7 +33,7 @@ private async Task> GetTransactionFeesMapAsync(IChainC
public async Task ChargeFee_With_Fork_Test()
{
var amount = 100000;
-
+
await SetMethodFeeWithProposalAsync(new MethodFees
{
MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
@@ -74,6 +74,7 @@ await SetMethodFeeWithProposalAsync(new MethodFees
BlockHash = branchOneBlock.GetHash(), BlockHeight = branchOneBlock.Height
});
transactionFeesMap.ShouldBeNull();
+
await SetMethodFeeWithProposalAsync(new MethodFees
{
MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
@@ -102,7 +103,7 @@ await SetMethodFeeWithProposalAsync(new MethodFees
BlockHash = result.Item1.GetHash(), BlockHeight = result.Item1.Height
});
transactionFeesMap.First().Value.ShouldBe(fee); //300000
- targetFee.ShouldNotBe(fee);
+ targetFee.ShouldBe(fee);
}
// branch two
@@ -128,18 +129,20 @@ await SetMethodFeeWithProposalAsync(new MethodFees
public async Task Claim_Fee_Send_By_User_Fail_Test()
{
var amount = 100000;
- await SetMethodFeeWithProposalAsync(new MethodFees
- {
- MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
- Fees =
+
+ await Tester.ExecuteContractWithMiningAsync(TokenContractAddress,
+ nameof(TokenContractImplContainer.TokenContractImplStub.SetMethodFee), new MethodFees
{
- new MethodFee
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Transfer),
+ Fees =
{
- Symbol = "ELF",
- BasicFee = amount
+ new MethodFee
+ {
+ Symbol = "ELF",
+ BasicFee = amount
+ }
}
- }
- }.ToByteString());
+ });
await Tester.ExecuteContractWithMiningReturnBlockAsync(TokenContractAddress,
nameof(TokenContractContainer.TokenContractStub.Transfer), new TransferInput
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForUserContractMethodFeeTest.cs b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForUserContractMethodFeeTest.cs
index f10baf828c..25e8daa5f4 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForUserContractMethodFeeTest.cs
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForUserContractMethodFeeTest.cs
@@ -155,7 +155,7 @@ public async Task GetPreTransactions_None_PreTransaction_Test()
[InlineData(9, 0, 1, 10, 1, 2, "ELF", 9, false)]
[InlineData(100000000, 2, 2, 0, 1, 2, "TSA", 1, true)]
[InlineData(100000000, 2, 2, 0, 13, 2, "TSB", 2, true)]
- [InlineData(100000000, 2, 2, 0, 20, 20, "TSB", 2, false)]
+ [InlineData(100000000, 2, 2, 0, 20, 20, "TSA", 2, false)]
[InlineData(1, 0, 1, 0, 1, 2, "TSB", 1, false)]
[InlineData(10, 0, 0, 0, 1, 2, "ELF", 10, false)] // Charge 10 ELFs tx size fee.
public async Task ChargeFee_SetConfiguration_Tests(long balance1, long balance2, long balance3, long fee1,
@@ -184,14 +184,8 @@ await TokenContractStub.Transfer.SendAsync(new TransferInput
Key = ConfigurationKey,
Value = transactionFee.ToByteString()
};
- {
- var organizationAddress = await GetParliamentDefaultOrganizationAddressAsync();
- var proposalId =
- await CreateProposalAsync(organizationAddress, createProposalInput, "SetConfiguration");
- await ParliamentContractStub.Approve.SendAsync(proposalId);
- var releaseRet = await ParliamentContractStub.Release.SendAsync(proposalId);
- releaseRet.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
- }
+
+ await ConfigurationStub.SetConfiguration.SendAsync(createProposalInput);
var originBalance = (await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
@@ -250,14 +244,7 @@ public async Task ChargeFee_SizeFeeIsFree()
Key = ConfigurationKey,
Value = transactionFee.ToByteString()
};
- {
- var organizationAddress = await GetParliamentDefaultOrganizationAddressAsync();
- var proposalId =
- await CreateProposalAsync(organizationAddress, createProposalInput, "SetConfiguration");
- await ParliamentContractStub.Approve.SendAsync(proposalId);
- var releaseRet = await ParliamentContractStub.Release.SendAsync(proposalId);
- releaseRet.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
- }
+ await ConfigurationStub.SetConfiguration.SendAsync(createProposalInput);
var beforeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
Owner = DefaultAddress,
@@ -298,14 +285,7 @@ public async Task ChargeFee_SpecConfigurationFee()
Key = $"{ConfigurationKey}_{_testContractAddress}_{nameof(TestContractContainer.TestContractStub.TestMethod)}",
Value = transactionFee.ToByteString()
};
- {
- var organizationAddress = await GetParliamentDefaultOrganizationAddressAsync();
- var proposalId =
- await CreateProposalAsync(organizationAddress, createProposalInput, "SetConfiguration");
- await ParliamentContractStub.Approve.SendAsync(proposalId);
- var releaseRet = await ParliamentContractStub.Release.SendAsync(proposalId);
- releaseRet.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
- }
+ await ConfigurationStub.SetConfiguration.SendAsync(createProposalInput);
var beforeBalance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
Owner = DefaultAddress,
@@ -334,7 +314,8 @@ await TokenContractStub.Create.SendAsync(new CreateInput
IsBurnable = true,
TokenName = "test token",
TotalSupply = 1_000_000_00000000L,
- Issuer = DefaultAddress
+ Issuer = DefaultAddress,
+ Owner = DefaultAddress,
});
if (issueAmount != 0)
@@ -363,10 +344,7 @@ private async Task Initialize()
await DeployTestContractAsync();
{
- var proposalId = await SetUserContractFeeAsync(1_00000000);
- await ParliamentContractStub.Approve.SendAsync(proposalId);
- var releaseRet = await ParliamentContractStub.Release.SendAsync(proposalId);
- releaseRet.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ await SetUserContractFeeAsync(1_00000000);
var configuration = await ConfigurationStub.GetConfiguration.CallAsync(new StringValue
{
Value = ConfigurationKey
@@ -390,13 +368,10 @@ private async Task CheckTransactionFeesMapAsync(Dictionary transac
transactionFeesMap.Value[transactionFee.Key].ShouldBe(transactionFee.Value);
}
- private async Task SetUserContractFeeAsync(int amount)
+ private async Task SetUserContractFeeAsync(int amount)
{
var createProposalInput = SetUserContractFee(amount);
- var organizationAddress = await GetParliamentDefaultOrganizationAddressAsync();
- var proposalId =
- await CreateProposalAsync(organizationAddress, createProposalInput, "SetConfiguration");
- return proposalId;
+ await ConfigurationStub.SetConfiguration.SendAsync(createProposalInput);
}
private async Task GetParliamentDefaultOrganizationAddressAsync()
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/MethodFeeTestTokenContractInitializationProvider.cs b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/MethodFeeTestTokenContractInitializationProvider.cs
index 38cc9592d0..585a902412 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/MethodFeeTestTokenContractInitializationProvider.cs
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/MethodFeeTestTokenContractInitializationProvider.cs
@@ -28,7 +28,8 @@ public MethodFeeTestTokenContractInitializationProvider() : base(null)
IsBurnable = true,
TokenName = "elf token",
TotalSupply = 1_000_000_00000000L,
- Issuer = SampleAccount.Accounts[0].Address
+ Issuer = SampleAccount.Accounts[0].Address,
+ Owner = SampleAccount.Accounts[0].Address
}.ToByteString()
});
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests.csproj b/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests.csproj
index 360e3a5f34..6413e7f543 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests.csproj
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests.csproj
@@ -9,7 +9,7 @@
runtime; build; native; contentfiles; analyzers
-
+
all
@@ -21,11 +21,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -53,12 +53,12 @@
Contract
PreserveNewest
-
+
false
Contract
PreserveNewest
-
+
false
Contract
PreserveNewest
@@ -103,12 +103,12 @@
Protobuf\Proto\acs10.proto
-
- Protobuf\Proto\parliament_contract.proto
-
Protobuf\Proto\aedpos_contract.proto
+
+ Protobuf\Proto\test_mock_parliament_contract.proto
+
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/ExecutionPluginForResourceFeeTestBase.cs b/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/ExecutionPluginForResourceFeeTestBase.cs
index 7d73b285db..7f641bdb82 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/ExecutionPluginForResourceFeeTestBase.cs
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/ExecutionPluginForResourceFeeTestBase.cs
@@ -4,6 +4,7 @@
using AElf.Contracts.Consensus.AEDPoS;
using AElf.Contracts.MultiToken;
using AElf.Contracts.Parliament;
+using AElf.Contracts.TestContract.MockParliament;
using AElf.Contracts.TokenConverter;
using AElf.Contracts.Treasury;
using AElf.ContractTestKit;
@@ -119,11 +120,12 @@ public class ExecutionPluginForResourceFeeTestBase : ContractTestBase Accounts[0].KeyPair;
@@ -139,11 +141,11 @@ public class ExecutionPluginForResourceFeeTestBase : ContractTestBase kv.Key.Contains("TestContract")).Value;
+ var code = Codes.Single(kv => kv.Key.Contains("ExecutionPluginForResourceFee.Tests.TestContract")).Value;
TestContractAddress = await DeployContractAsync(category, code, HashHelper.ComputeFrom("TestContract"),
DefaultSenderKeyPair);
TestContractStub =
@@ -196,11 +198,11 @@ await DeploySystemSmartContract(category, code,
// Parliament
{
- var code = Codes.Single(kv => kv.Key.Contains("Parliament")).Value;
- var parliamentContractAddress = await DeploySystemSmartContract(category, code,
+ var code = Codes.Single(kv => kv.Key.Contains("MockParliament")).Value;
+ ParliamentContractAddress = await DeploySystemSmartContract(category, code,
ParliamentSmartContractAddressNameProvider.Name, DefaultSenderKeyPair);
ParliamentContractStub =
- GetTester(parliamentContractAddress,
+ GetTester(ParliamentContractAddress,
DefaultSenderKeyPair);
}
@@ -222,18 +224,17 @@ private async Task InitializeTokenAsync()
const long issueAmountToConverter = 100_000_000_00000000;
//init elf token
{
- var createResult = await TokenContractStub.Create.SendAsync(new CreateInput
- {
- Symbol = "ELF",
- Decimals = 8,
- IsBurnable = true,
- TokenName = "elf token",
- TotalSupply = totalSupply,
- Issuer = DefaultSender,
- LockWhiteList = { TreasuryContractAddress, TokenConverterAddress }
- });
-
- createResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ await TokenContractStub.Create.SendAsync(new CreateInput
+ {
+ Symbol = "ELF",
+ Decimals = 8,
+ IsBurnable = true,
+ TokenName = "elf token",
+ TotalSupply = totalSupply,
+ Issuer = DefaultSender,
+ Owner = DefaultSender,
+ LockWhiteList = { TreasuryContractAddress, TokenConverterAddress }
+ });
{
var issueResult = await TokenContractStub.Issue.SendAsync(new IssueInput
@@ -258,7 +259,7 @@ private async Task InitializeTokenAsync()
//init resource token - CPU
{
- var createResult = await TokenContractStub.Create.SendAsync(new CreateInput
+ await TokenContractStub.Create.SendAsync(new CreateInput
{
Symbol = "READ",
Decimals = 2,
@@ -266,11 +267,10 @@ private async Task InitializeTokenAsync()
TokenName = "read token",
TotalSupply = totalSupply,
Issuer = DefaultSender,
+ Owner = DefaultSender,
LockWhiteList = { TreasuryContractAddress, TokenConverterAddress }
});
- createResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
-
var issueResult = await TokenContractStub.Issue.SendAsync(new IssueInput
{
Symbol = "READ",
@@ -283,7 +283,7 @@ private async Task InitializeTokenAsync()
//init resource token - STO
{
- var createResult = await TokenContractStub.Create.SendAsync(new CreateInput
+ await TokenContractStub.Create.SendAsync(new CreateInput
{
Symbol = "STORAGE",
Decimals = 2,
@@ -291,11 +291,10 @@ private async Task InitializeTokenAsync()
TokenName = "sto token",
TotalSupply = totalSupply,
Issuer = DefaultSender,
+ Owner = DefaultSender,
LockWhiteList = { TreasuryContractAddress, TokenConverterAddress }
});
- createResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
-
var issueResult = await TokenContractStub.Issue.SendAsync(new IssueInput
{
Symbol = "STORAGE",
@@ -308,7 +307,7 @@ private async Task InitializeTokenAsync()
//init resource token - NET
{
- var createResult = await TokenContractStub.Create.SendAsync(new CreateInput
+ await TokenContractStub.Create.SendAsync(new CreateInput
{
Symbol = "TRAFFIC",
Decimals = 2,
@@ -316,11 +315,10 @@ private async Task InitializeTokenAsync()
TokenName = "net token",
TotalSupply = totalSupply,
Issuer = DefaultSender,
+ Owner = DefaultSender,
LockWhiteList = { TreasuryContractAddress, TokenConverterAddress }
});
- createResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
-
var issueResult = await TokenContractStub.Issue.SendAsync(new IssueInput
{
Symbol = "TRAFFIC",
@@ -332,7 +330,7 @@ private async Task InitializeTokenAsync()
}
//init resource token - WRITE
{
- var createResult = await TokenContractStub.Create.SendAsync(new CreateInput
+ await TokenContractStub.Create.SendAsync(new CreateInput
{
Symbol = "WRITE",
Decimals = 2,
@@ -340,11 +338,10 @@ private async Task InitializeTokenAsync()
TokenName = "WRITE token",
TotalSupply = totalSupply,
Issuer = DefaultSender,
+ Owner = DefaultSender,
LockWhiteList = { TreasuryContractAddress, TokenConverterAddress }
});
- createResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
-
var issueResult = await TokenContractStub.Issue.SendAsync(new IssueInput
{
Symbol = "WRITE",
@@ -390,7 +387,11 @@ await TreasuryContractStub.InitialMiningRewardProfitItem.SendAsync(
private async Task InitializeParliament()
{
- await ParliamentContractStub.Initialize.SendAsync(new Contracts.Parliament.InitializeInput());
+ await ParliamentContractStub.Initialize.SendAsync(new AElf.Contracts.TestContract.MockParliament.InitializeInput
+ {
+ ProposerAuthorityRequired = false,
+ PrivilegedProposer = DefaultSender
+ });
}
private async Task InitializeAElfConsensus()
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/ExecutionPluginForResourceFeeTestModule.cs b/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/ExecutionPluginForResourceFeeTestModule.cs
index 22d634ad0b..3fb9d1c466 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/ExecutionPluginForResourceFeeTestModule.cs
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/ExecutionPluginForResourceFeeTestModule.cs
@@ -1,4 +1,5 @@
using AElf.ContractTestKit;
+using AElf.Kernel.Consensus.AEDPoS;
using AElf.Kernel.FeeCalculation;
using AElf.Kernel.FeeCalculation.Infrastructure;
using AElf.Kernel.SmartContract.Application;
diff --git a/test/AElf.OS.TestBase/OSTestHelper.cs b/test/AElf.OS.TestBase/OSTestHelper.cs
index a2f430808f..cbef7de0eb 100644
--- a/test/AElf.OS.TestBase/OSTestHelper.cs
+++ b/test/AElf.OS.TestBase/OSTestHelper.cs
@@ -432,7 +432,23 @@ private async Task StartNodeAsync()
TotalSupply = TokenTotalSupply,
Decimals = 2,
Issuer = ownAddress,
- IsBurnable = true
+ IsBurnable = true,
+ Owner = ownAddress
+ }.ToByteString()
+ });
+
+ tokenContractDto
+ .AddGenesisTransactionMethodCall(new ContractInitializationMethodCall
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Create), Params = new CreateInput
+ {
+ Symbol = "TELF",
+ TokenName = "ELF_Token",
+ TotalSupply = TokenTotalSupply,
+ Decimals = 2,
+ Issuer = ownAddress,
+ IsBurnable = true,
+ Owner = ownAddress
}.ToByteString()
});
@@ -452,6 +468,16 @@ private async Task StartNodeAsync()
Memo = "Issue"
}.ToByteString()
});
+ tokenContractDto.AddGenesisTransactionMethodCall(new ContractInitializationMethodCall
+ {
+ MethodName = nameof(TokenContractContainer.TokenContractStub.Issue), Params = new IssueInput
+ {
+ Symbol = "TELF",
+ Amount = TokenTotalSupply,
+ To = ownAddress,
+ Memo = "Issue"
+ }.ToByteString()
+ });
tokenContractDto.AddGenesisTransactionMethodCall(new ContractInitializationMethodCall
{
diff --git a/test/AElf.OS.Tests/Account/Application/AccountServiceTests.cs b/test/AElf.OS.Tests/Account/Application/AccountServiceTests.cs
index 399bdd6064..d00503a5eb 100644
--- a/test/AElf.OS.Tests/Account/Application/AccountServiceTests.cs
+++ b/test/AElf.OS.Tests/Account/Application/AccountServiceTests.cs
@@ -99,4 +99,15 @@ public async Task GetAccountAsync_WithOptionEmpty()
account = await _accountService.GetAccountAsync();
account.ShouldNotBeNull();
}
+
+ [Fact]
+ public async Task Vrf_Test()
+ {
+ var alpha = "5cf8151010716e40e5349ad02821da605df22e9ac95450c7e35f04c720fd4db5";
+ var alphaBytes = Hash.LoadFromHex(alpha).ToByteArray();
+ var pi = await _accountService.ECVrfProveAsync(alphaBytes);
+ var pubkey = await _accountService.GetPublicKeyAsync();
+ var beta = CryptoHelper.ECVrfVerify(pubkey, alphaBytes, pi);
+ beta.ShouldNotBeEmpty();
+ }
}
\ No newline at end of file
diff --git a/test/AElf.Parallel.Tests/ParallelTestHelper.cs b/test/AElf.Parallel.Tests/ParallelTestHelper.cs
index e2b523791f..94934e37d8 100644
--- a/test/AElf.Parallel.Tests/ParallelTestHelper.cs
+++ b/test/AElf.Parallel.Tests/ParallelTestHelper.cs
@@ -173,37 +173,22 @@ await _smartContractAddressService.GetAddressByContractNameAsync(await GetChainC
return GetBalanceOutput.Parser.ParseFrom(returnValue).Balance;
}
- public async Task CreateAndIssueTokenAsync(string symbol, Address issueAddress)
+ public async Task TransferTokenAsync(string symbol, Address issueAddress)
{
var ownAddress = await _accountService.GetAccountAsync();
var tokenContractAddress =
await _smartContractAddressService.GetAddressByContractNameAsync(await GetChainContextAsync(),
TokenSmartContractAddressNameProvider.StringName);
- var createTokenTransaction = GenerateTransaction(ownAddress, tokenContractAddress,
- nameof(TokenContractContainer.TokenContractStub.Create),
- new CreateInput
- {
- Symbol = symbol,
- TokenName = $"{symbol}_Token",
- TotalSupply = TokenTotalSupply,
- Decimals = 2,
- Issuer = ownAddress,
- IsBurnable = true
- });
- var signature = await _accountService.SignAsync(createTokenTransaction.GetHash().ToByteArray());
- createTokenTransaction.Signature = ByteString.CopyFrom(signature);
- await BroadcastTransactions(new List { createTokenTransaction });
- await MinedOneBlock();
-
+
var issueTokenTransaction = GenerateTransaction(ownAddress, tokenContractAddress,
- nameof(TokenContractContainer.TokenContractStub.Issue), new IssueInput
+ nameof(TokenContractContainer.TokenContractStub.Transfer), new TransferInput
{
Symbol = symbol,
- Amount = TokenTotalSupply,
+ Amount = 100_000000,
To = issueAddress,
- Memo = "Issue"
+ Memo = "Transfer"
});
- signature = await _accountService.SignAsync(issueTokenTransaction.GetHash().ToByteArray());
+ var signature = await _accountService.SignAsync(issueTokenTransaction.GetHash().ToByteArray());
issueTokenTransaction.Signature = ByteString.CopyFrom(signature);
await BroadcastTransactions(new List { issueTokenTransaction });
await MinedOneBlock();
diff --git a/test/AElf.Parallel.Tests/ParallelTests.cs b/test/AElf.Parallel.Tests/ParallelTests.cs
index b0dbbd5e5a..19b8452e24 100644
--- a/test/AElf.Parallel.Tests/ParallelTests.cs
+++ b/test/AElf.Parallel.Tests/ParallelTests.cs
@@ -224,7 +224,7 @@ public async Task TransferTwoSymbolParallelTest()
var symbol = "TELF";
var keyPair = CryptoHelper.GenerateKeyPair();
var address = Address.FromPublicKey(keyPair.PublicKey);
- await _parallelTestHelper.CreateAndIssueTokenAsync(symbol, address);
+ await _parallelTestHelper.TransferTokenAsync(symbol, address);
var transactionList = new List();
var accountAddress = await _accountService.GetAccountAsync();
diff --git a/test/AElf.WebApp.Application.Chain.Tests/AElf.WebApp.Application.Chain.Tests.csproj b/test/AElf.WebApp.Application.Chain.Tests/AElf.WebApp.Application.Chain.Tests.csproj
index f4907935f6..f629badebd 100644
--- a/test/AElf.WebApp.Application.Chain.Tests/AElf.WebApp.Application.Chain.Tests.csproj
+++ b/test/AElf.WebApp.Application.Chain.Tests/AElf.WebApp.Application.Chain.Tests.csproj
@@ -9,7 +9,7 @@
runtime; build; native; contentfiles; analyzers
-
+
all
@@ -20,14 +20,19 @@
runtime; build; native; contentfiles; analyzers
-
+
-
+
false
Contract
PreserveNewest
+
+ false
+ Contract
+ PreserveNewest
+
diff --git a/test/AElf.WebApp.Application.Chain.Tests/BlockChainAppServiceTest.cs b/test/AElf.WebApp.Application.Chain.Tests/BlockChainAppServiceTest.cs
index 6755b238ee..b898977dc3 100644
--- a/test/AElf.WebApp.Application.Chain.Tests/BlockChainAppServiceTest.cs
+++ b/test/AElf.WebApp.Application.Chain.Tests/BlockChainAppServiceTest.cs
@@ -66,7 +66,8 @@ public BlockChainAppServiceTest(ITestOutputHelper outputHelper) : base(outputHel
_codes ?? (_codes = ContractsDeployer.GetContractCodes());
private byte[] TestContractCode => Codes.Single(kv => kv.Key.Contains("TestContract.BasicFunction")).Value;
- private byte[] VoteContractCode => Codes.Single(kv => kv.Key.Contains("Vote")).Value;
+ private byte[] VoteContractCode => Codes.Single(kv => kv.Key.Contains("Contracts.Vote")).Value;
+ private byte[] TestVoteContractCode => Codes.Single(kv => kv.Key.Contains("TestContract.Vote")).Value;
[Fact]
public async Task Deploy_Contract_Success_Test()
@@ -1720,5 +1721,105 @@ await PostResponseAsObjectAsync("/api/blockChain/CalculateT
response.Error.Message.ShouldBe(Error.Message[Error.InvalidParams]);
}
+ [Fact]
+ public async Task Transaction_Params_Changed_Test()
+ {
+ var accountAddress = await _accountService.GetAccountAsync();
+ var chain = await _blockchainService.GetChainAsync();
+ var deployTransaction = new Transaction
+ {
+ From = accountAddress,
+ To = _smartContractAddressService.GetZeroSmartContractAddress(),
+ MethodName = nameof(BasicContractZero.DeploySmartContract),
+ Params = ByteString.CopyFrom(new ContractDeploymentInput
+ {
+ Category = KernelConstants.CodeCoverageRunnerCategory,
+ Code = ByteString.CopyFrom(VoteContractCode)
+ }.ToByteArray()),
+ RefBlockNumber = chain.BestChainHeight,
+ RefBlockPrefix = BlockHelper.GetRefBlockPrefix(chain.BestChainHash)
+ };
+ deployTransaction.Signature =
+ ByteString.CopyFrom(await _accountService.SignAsync(deployTransaction.GetHash().ToByteArray()));
+
+ var parameters = new Dictionary
+ {
+ { "rawTransaction", deployTransaction.ToByteArray().ToHex() }
+ };
+
+ var sendTransactionResponse =
+ await PostResponseAsObjectAsync("/api/blockChain/sendTransaction",
+ parameters);
+
+ sendTransactionResponse.TransactionId.ShouldBe(deployTransaction.GetHash().ToHex());
+ await _osTestHelper.MinedOneBlock();
+ var transactionResult = await _osTestHelper.GetTransactionResultsAsync(deployTransaction.GetHash());
+ transactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ var address = Address.Parser.ParseFrom(transactionResult.ReturnValue);
+ var transaction = new Transaction
+ {
+ From = accountAddress,
+ To = address,
+ MethodName = nameof(VoteContractContainer.VoteContractStub.AddOption),
+ Params = ByteString.CopyFrom(new AddOptionInput()
+ {
+ VotingItemId = HashHelper.ComputeFrom("VotingItemId"),
+ Option = "Option"
+ }.ToByteArray()),
+ RefBlockNumber = chain.BestChainHeight,
+ RefBlockPrefix = BlockHelper.GetRefBlockPrefix(chain.BestChainHash)
+ };
+ transaction.Signature =
+ ByteString.CopyFrom(await _accountService.SignAsync(transaction.GetHash().ToByteArray()));
+
+ parameters = new Dictionary
+ {
+ { "rawTransaction", transaction.ToByteArray().ToHex() }
+ };
+
+ sendTransactionResponse =
+ await PostResponseAsObjectAsync("/api/blockChain/sendTransaction",
+ parameters);
+
+ sendTransactionResponse.TransactionId.ShouldBe(transaction.GetHash().ToHex());
+ await _osTestHelper.MinedOneBlock();
+ var response = await GetResponseAsObjectAsync(
+ $"/api/blockChain/transactionResult?transactionId={transaction.GetHash().ToHex()}");
+ response.Transaction.Params.ShouldBe(AddOptionInput.Parser.ParseFrom(transaction.Params).ToString());
+
+ var updateTransaction = new Transaction
+ {
+ From = accountAddress,
+ To = _smartContractAddressService.GetZeroSmartContractAddress(),
+ MethodName = nameof(BasicContractZero.UpdateSmartContract),
+ Params = ByteString.CopyFrom(new ContractUpdateInput
+ {
+ Address = address,
+ Code = ByteString.CopyFrom(TestVoteContractCode)
+ }.ToByteArray()),
+ RefBlockNumber = chain.BestChainHeight,
+ RefBlockPrefix = BlockHelper.GetRefBlockPrefix(chain.BestChainHash)
+ };
+ updateTransaction.Signature =
+ ByteString.CopyFrom(await _accountService.SignAsync(updateTransaction.GetHash().ToByteArray()));
+
+ parameters = new Dictionary
+ {
+ { "rawTransaction", updateTransaction.ToByteArray().ToHex() }
+ };
+ sendTransactionResponse =
+ await PostResponseAsObjectAsync("/api/blockChain/sendTransaction",
+ parameters);
+
+ sendTransactionResponse.TransactionId.ShouldBe(updateTransaction.GetHash().ToHex());
+ await _osTestHelper.MinedOneBlock();
+ transactionResult = await _osTestHelper.GetTransactionResultsAsync(updateTransaction.GetHash());
+ transactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ response = await GetResponseAsObjectAsync(
+ $"/api/blockChain/transactionResult?transactionId={transaction.GetHash().ToHex()}");
+ response.Transaction.Params.ShouldBe(transaction.Params.ToBase64());
+ response.Transaction.Params.ShouldNotBe(
+ AddOptionInput.Parser.ParseFrom(transaction.Params).ToString());
+ }
}
\ No newline at end of file