예제 #1
0
        public void SimpleTransfer()
        {
            var owner     = KeyPair.Generate();
            var simulator = new ChainSimulator(owner, 1234);

            var nexus = simulator.Nexus;

            var testUserA = KeyPair.Generate();
            var testUserB = KeyPair.Generate();

            var fuelAmount     = UnitConversion.ToBigInteger(10, Nexus.FuelTokenDecimals);
            var transferAmount = UnitConversion.ToBigInteger(10, Nexus.StakingTokenDecimals);

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, testUserA.Address, nexus.RootChain, Nexus.FuelTokenSymbol, fuelAmount);
            simulator.GenerateTransfer(owner, testUserA.Address, nexus.RootChain, Nexus.StakingTokenSymbol, transferAmount);
            simulator.EndBlock();

            // Send from user A to user B
            simulator.BeginBlock();
            simulator.GenerateTransfer(testUserA, testUserB.Address, nexus.RootChain, Nexus.StakingTokenSymbol, transferAmount);
            simulator.EndBlock();

            var finalBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUserB.Address);

            Assert.IsTrue(finalBalance == transferAmount);
        }
예제 #2
0
        public void SingleUploadSuccessMaxFileSize()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var testUser = KeyPair.Generate();

            BigInteger accountBalance = (Archive.MaxSize / 1024) / KilobytesPerStake;  //provide enough account balance for max file size available space

            accountBalance *= UnitConversion.GetUnitValue(Nexus.StakingTokenDecimals);

            Transaction tx = null;

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.FuelTokenSymbol, 100000000);
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.StakingTokenSymbol, accountBalance);
            simulator.EndBlock();

            //-----------
            //Perform a valid Stake call
            var stakeAmount         = accountBalance;
            var startingSoulBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUser.Address);

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("energy", "Stake", testUser.Address, stakeAmount).
                                                     SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            BigInteger stakedAmount = (BigInteger)simulator.Nexus.RootChain.InvokeContract("energy", "GetStake", testUser.Address);

            Assert.IsTrue(stakedAmount == stakeAmount);

            var finalSoulBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUser.Address);

            Assert.IsTrue(stakeAmount == startingSoulBalance - finalSoulBalance);

            //-----------
            //Upload a file: should succeed
            var filename      = "notAVirus.exe";
            var headerSize    = CalculateRequiredSize(filename, 0);
            var contentSize   = (long)(Archive.MaxSize) - (long)headerSize;
            var content       = new byte[contentSize];
            var contentMerkle = new MerkleTree(content);

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("storage", "UploadFile", testUser.Address, filename, contentSize, contentMerkle, ArchiveFlags.None, new byte[0]).
                                                     SpendGas(testUser.Address).EndScript());
            System.IO.File.WriteAllText(@"D:\Repos\bug_vm.txt", string.Join('\n', new VM.Disassembler(tx.Script).Instructions));
            simulator.EndBlock();

            var usedSpace = (BigInteger)simulator.Nexus.RootChain.InvokeContract("storage", "GetUsedSpace", testUser.Address);

            Assert.IsTrue(usedSpace == 0);
        }
예제 #3
0
        public void UploadBeyondAvailableSpace()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var testUser = KeyPair.Generate();

            var accountBalance = BaseEnergyRatioDivisor * 100;

            Transaction tx = null;

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.FuelTokenSymbol, 100000000);
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.StakingTokenSymbol, accountBalance);
            simulator.EndBlock();

            //-----------
            //Perform a valid Stake call for minimum staking amount
            var stakeAmount         = BaseEnergyRatioDivisor;
            var startingSoulBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUser.Address);

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("energy", "Stake", testUser.Address, stakeAmount).
                                                     SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            BigInteger stakedAmount = (BigInteger)simulator.Nexus.RootChain.InvokeContract("energy", "GetStake", testUser.Address);

            Assert.IsTrue(stakedAmount == stakeAmount);

            var finalSoulBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUser.Address);

            Assert.IsTrue(stakeAmount == startingSoulBalance - finalSoulBalance);

            //-----------
            //Upload a file: should fail due to exceeding available space
            var filename    = "notAVirus.exe";
            var headerSize  = (BigInteger)simulator.Nexus.RootChain.InvokeContract("storage", "CalculateRequiredSize", filename, 0);
            var contentSize = (long)(stakeAmount * KilobytesPerStake * 1024) - (long)headerSize;
            var content     = new byte[contentSize];

            Assert.ThrowsException <Exception>(() =>
            {
                simulator.BeginBlock();
                tx = simulator.GenerateCustomTransaction(testUser, () =>
                                                         ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                         .CallContract("storage", "UploadFile", testUser.Address, filename, contentSize * 2, content, ArchiveFlags.None).
                                                         SpendGas(testUser.Address).EndScript());
                simulator.EndBlock();
            })
            ;
            var usedSpace = (BigInteger)simulator.Nexus.RootChain.InvokeContract("storage", "GetUsedSpace", testUser.Address);

            Assert.IsTrue(usedSpace == 0);
        }
예제 #4
0
        public void NftBurn()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var chain = nexus.RootChain;

            var symbol = "COOL";

            var testUser = KeyPair.Generate();

            // Create the token CoolToken as an NFT
            simulator.BeginBlock();
            simulator.GenerateToken(owner, symbol, "CoolToken", 0, 0, Blockchain.Tokens.TokenFlags.None);
            simulator.EndBlock();

            // Send some SOUL to the test user (required for gas used in "burn" transaction)
            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, testUser.Address, chain, Nexus.FuelTokenSymbol, UnitConversion.ToBigInteger(1, Nexus.FuelTokenDecimals));
            simulator.EndBlock();

            var token     = simulator.Nexus.GetTokenInfo(symbol);
            var tokenData = new byte[] { 0x1, 0x3, 0x3, 0x7 };

            Assert.IsTrue(nexus.TokenExists(symbol), "Can't find the token symbol");

            // verify nft presence on the user pre-mint
            var ownedTokenList = chain.GetTokenOwnerships(symbol).Get(chain.Storage, testUser.Address);

            Assert.IsTrue(!ownedTokenList.Any(), "How does the user already have a CoolToken?");

            // Mint a new CoolToken directly on the user
            simulator.BeginBlock();
            simulator.GenerateNft(owner, testUser.Address, chain, symbol, tokenData, new byte[0]);
            simulator.EndBlock();

            // verify nft presence on the user post-mint
            ownedTokenList = chain.GetTokenOwnerships(symbol).Get(chain.Storage, testUser.Address);
            Assert.IsTrue(ownedTokenList.Count() == 1, "How does the user not have one now?");

            //verify that the present nft is the same we actually tried to create
            var tokenId = ownedTokenList.ElementAt(0);
            var nft     = nexus.GetNFT(symbol, tokenId);

            Assert.IsTrue(nft.ROM.SequenceEqual(tokenData) || nft.RAM.SequenceEqual(tokenData),
                          "And why is this NFT different than expected? Not the same data");

            // burn the token
            simulator.BeginBlock();
            simulator.GenerateNftBurn(testUser, chain, symbol, tokenId);
            simulator.EndBlock();

            //verify the user no longer has the token
            ownedTokenList = chain.GetTokenOwnerships(symbol).Get(chain.Storage, testUser.Address);
            Assert.IsTrue(!ownedTokenList.Any(), "How does the user still have it post-burn?");
        }
예제 #5
0
        public void SideChainTransferDifferentAccounts()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var sourceChain = nexus.RootChain;
            var targetChain = nexus.FindChainByName("privacy");

            var symbol = Nexus.FuelTokenSymbol;

            var sender   = KeyPair.Generate();
            var receiver = KeyPair.Generate();

            var token          = nexus.GetTokenInfo(symbol);
            var originalAmount = UnitConversion.ToBigInteger(10, token.Decimals);
            var sideAmount     = originalAmount / 2;

            Assert.IsTrue(sideAmount > 0);

            // Send from Genesis address to "sender" user
            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, sender.Address, nexus.RootChain, symbol, originalAmount);
            simulator.EndBlock();

            // verify test user balance
            var balance = nexus.RootChain.GetTokenBalance(symbol, sender.Address);

            Assert.IsTrue(balance == originalAmount);

            var crossFee = UnitConversion.ToBigInteger(0.001m, token.Decimals);

            // do a side chain send using test user balance from root to account chain
            simulator.BeginBlock();
            var txA = simulator.GenerateSideChainSend(sender, symbol, sourceChain, receiver.Address, targetChain, sideAmount, crossFee);

            simulator.EndBlock();
            var blockA = nexus.RootChain.LastBlock;

            // finish the chain transfer
            simulator.BeginBlock();
            var txB = simulator.GenerateSideChainSettlement(receiver, nexus.RootChain, targetChain, blockA.Hash);

            Assert.IsTrue(simulator.EndBlock().Any());

            // verify balances
            var feeB = targetChain.GetTransactionFee(txB);

            balance = targetChain.GetTokenBalance(symbol, receiver.Address);
            Assert.IsTrue(balance == sideAmount - feeB);

            var feeA           = sourceChain.GetTransactionFee(txA);
            var leftoverAmount = originalAmount - (sideAmount + feeA + crossFee);

            balance = sourceChain.GetTokenBalance(symbol, sender.Address);
            Assert.IsTrue(balance == leftoverAmount);
        }
예제 #6
0
        public void NftMint()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var chain = nexus.RootChain;

            var symbol = "COOL";

            var testUser = KeyPair.Generate();

            // Create the token CoolToken as an NFT
            simulator.BeginBlock();
            simulator.GenerateToken(owner, symbol, "CoolToken", 0, 0, Blockchain.Tokens.TokenFlags.None);
            simulator.EndBlock();

            var token = simulator.Nexus.GetTokenInfo(symbol);

            Assert.IsTrue(nexus.TokenExists(symbol), "Can't find the token symbol");

            // verify nft presence on the user pre-mint
            var ownerships     = new OwnershipSheet(symbol);
            var ownedTokenList = ownerships.Get(chain.Storage, testUser.Address);

            Assert.IsTrue(!ownedTokenList.Any(), "How does the sender already have a CoolToken?");

            var tokenROM = new byte[] { 0x1, 0x3, 0x3, 0x7 };
            var tokenRAM = new byte[] { 0x1, 0x4, 0x4, 0x6 };

            // Mint a new CoolToken directly on the user
            simulator.BeginBlock();
            simulator.GenerateNft(owner, testUser.Address, symbol, tokenROM, tokenRAM);
            simulator.EndBlock();

            // verify nft presence on the user post-mint
            ownedTokenList = ownerships.Get(chain.Storage, testUser.Address);
            Assert.IsTrue(ownedTokenList.Count() == 1, "How does the sender not have one now?");

            //verify that the present nft is the same we actually tried to create
            var tokenId = ownedTokenList.ElementAt(0);
            var nft     = nexus.GetNFT(symbol, tokenId);

            Assert.IsTrue(nft.ROM.SequenceEqual(tokenROM) && nft.RAM.SequenceEqual(tokenRAM),
                          "And why is this NFT different than expected? Not the same data");

            var currentSupply = nexus.GetTokenSupply(chain.Storage, symbol);

            Assert.IsTrue(currentSupply == 1, "why supply did not increase?");
        }
예제 #7
0
        public void TestNoGasSameChainTransfer()
        {
            var owner     = KeyPair.Generate();
            var simulator = new ChainSimulator(owner, 1234);

            var nexus        = simulator.Nexus;
            var accountChain = nexus.FindChainByName("account");

            var symbol = Nexus.FuelTokenSymbol;
            var token  = nexus.GetTokenInfo(symbol);

            var sender   = KeyPair.Generate();
            var receiver = KeyPair.Generate();

            var amount = UnitConversion.ToBigInteger(400, token.Decimals);

            var oldBalance = nexus.RootChain.GetTokenBalance(symbol, owner.Address);

            // Send from Genesis address to test user
            simulator.BeginBlock();
            var tx = simulator.GenerateTransfer(owner, sender.Address, nexus.RootChain, symbol, amount);

            simulator.EndBlock();

            // verify test user balance
            var transferBalance = nexus.RootChain.GetTokenBalance(symbol, sender.Address);

            Assert.IsTrue(transferBalance == amount);

            var newBalance = nexus.RootChain.GetTokenBalance(symbol, owner.Address);
            var gasFee     = nexus.RootChain.GetTransactionFee(tx);

            Assert.IsTrue(transferBalance + newBalance + gasFee == oldBalance);

            //Try to send the entire balance without affording fees from sender to receiver
            try
            {
                simulator.BeginBlock();
                tx = simulator.GenerateTransfer(sender, receiver.Address, nexus.RootChain, symbol, transferBalance);
                simulator.EndBlock();
            }
            catch (Exception e)
            {
                Assert.IsNotNull(e);
            }

            // verify balances, receiver should have 0 balance
            transferBalance = nexus.RootChain.GetTokenBalance(symbol, receiver.Address);
            Assert.IsTrue(transferBalance == 0, "Transaction failed completely as expected");
        }
예제 #8
0
        public void FungibleTokenTransfer()
        {
            var owner     = KeyPair.Generate();
            var simulator = new ChainSimulator(owner, 1234);

            var nexus        = simulator.Nexus;
            var accountChain = nexus.FindChainByName("account");
            var symbol       = Nexus.FuelTokenSymbol;
            var token        = nexus.GetTokenInfo(symbol);

            var testUser = KeyPair.Generate();

            var amount = UnitConversion.ToBigInteger(2, token.Decimals);

            var oldBalance = nexus.RootChain.GetTokenBalance(symbol, owner.Address);

            Assert.IsTrue(oldBalance > amount);

            // Send from Genesis address to test user
            simulator.BeginBlock();
            var tx = simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, symbol, amount);

            simulator.EndBlock();

            // verify test user balance
            var transferBalance = nexus.RootChain.GetTokenBalance(symbol, testUser.Address);

            Assert.IsTrue(transferBalance == amount);

            var newBalance = nexus.RootChain.GetTokenBalance(symbol, owner.Address);
            var gasFee     = nexus.RootChain.GetTransactionFee(tx);

            Assert.IsTrue(transferBalance + newBalance + gasFee == oldBalance);
        }
예제 #9
0
 private void TopUpChannel(ChainSimulator simulator, KeyPair from, BigInteger amount)
 {
     simulator.BeginBlock();
     simulator.GenerateCustomTransaction(from, ProofOfWork.None, () =>
                                         ScriptUtils.BeginScript().AllowGas(from.Address, Address.Null, 1, 9999)
                                         .CallContract("relay", "TopUpChannel", from.Address, amount).
                                         SpendGas(from.Address).EndScript());
     simulator.EndBlock();
 }
예제 #10
0
        public void CreateNonDivisibleToken()
        {
            var owner     = KeyPair.Generate();
            var simulator = new ChainSimulator(owner, 1234);

            var nexus        = simulator.Nexus;
            var accountChain = nexus.FindChainByName("account");
            var symbol       = "BLA";

            var tokenSupply = UnitConversion.ToBigInteger(100000000, 18);

            simulator.BeginBlock();
            simulator.GenerateToken(owner, symbol, "BlaToken", tokenSupply, 0, TokenFlags.Transferable | TokenFlags.Fungible | TokenFlags.Finite);
            simulator.MintTokens(owner, symbol, tokenSupply);
            simulator.EndBlock();

            var token = nexus.GetTokenInfo(symbol);

            var testUser = KeyPair.Generate();

            var amount = UnitConversion.ToBigInteger(2, token.Decimals);

            var oldBalance = nexus.RootChain.GetTokenBalance(symbol, owner.Address);

            Assert.IsTrue(oldBalance > amount);

            // Send from Genesis address to test user
            simulator.BeginBlock();
            var tx = simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, symbol, amount);

            simulator.EndBlock();

            // verify test user balance
            var transferBalance = nexus.RootChain.GetTokenBalance(symbol, testUser.Address);

            Assert.IsTrue(transferBalance == amount);

            var newBalance = nexus.RootChain.GetTokenBalance(symbol, owner.Address);

            Assert.IsTrue(transferBalance + newBalance == oldBalance);
        }
예제 #11
0
        public void UnstakeAfterUsedSpaceRelease()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var testUser = KeyPair.Generate();

            var accountBalance = MinimumValidStake * 100;

            Transaction tx = null;

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.FuelTokenSymbol, 100000000);
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.StakingTokenSymbol, accountBalance);
            simulator.EndBlock();

            //-----------
            //Perform a valid Stake call for minimum staking amount
            var stakedAmount        = MinimumValidStake;
            var startingSoulBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUser.Address);

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, ProofOfWork.None, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("energy", "Stake", testUser.Address, stakedAmount).
                                                     SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            //-----------
            //Upload a file
            var filename = "notAVirus.exe";

            var headerSize  = CalculateRequiredSize(filename, 0);
            var contentSize = (long)(stakedAmount / MinimumValidStake * KilobytesPerStake * 1024) - (long)headerSize;
            var content     = new byte[contentSize];

            var contentMerkle = new MerkleTree(content);

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, ProofOfWork.None, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("storage", "UploadFile", testUser.Address, filename, contentSize, contentMerkle, ArchiveFlags.None, new byte[0]).
                                                     SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            var usedSpace = simulator.Nexus.RootChain.InvokeContract("storage", "GetUsedSpace", testUser.Address).AsNumber();

            Assert.IsTrue(usedSpace == contentSize + headerSize);

            //-----------
            //Delete the file

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, ProofOfWork.None, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("storage", "DeleteFile", testUser.Address, filename).
                                                     SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            usedSpace = simulator.Nexus.RootChain.InvokeContract("storage", "GetUsedSpace", testUser.Address).AsNumber();

            Assert.IsTrue(usedSpace == 0);

            //-----------
            //Time skip 1 day
            simulator.TimeSkipDays(1);

            //-----------
            //Try to unstake everything: should succeed
            simulator.BeginBlock();
            simulator.GenerateCustomTransaction(testUser, ProofOfWork.None, () =>
                                                ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                .CallContract("energy", "Unstake", testUser.Address, stakedAmount).
                                                SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            var finalStakedAmount = simulator.Nexus.RootChain.InvokeContract("energy", "GetStake", testUser.Address).AsNumber();

            Assert.IsTrue(finalStakedAmount == 0);
        }
예제 #12
0
        public void SidechainNftTransfer()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var sourceChain = nexus.RootChain;
            var targetChain = nexus.FindChainByName("privacy");

            var nftSymbol = "COOL";

            var sender   = KeyPair.Generate();
            var receiver = KeyPair.Generate();

            var fullAmount  = UnitConversion.ToBigInteger(10, Nexus.FuelTokenDecimals);
            var smallAmount = fullAmount / 2;

            Assert.IsTrue(smallAmount > 0);

            // Send some SOUL to the test user (required for gas used in "transfer" transaction)
            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, sender.Address, sourceChain, Nexus.FuelTokenSymbol, fullAmount);
            simulator.EndBlock();

            // Create the token CoolToken as an NFT
            simulator.BeginBlock();
            simulator.GenerateToken(owner, nftSymbol, "CoolToken", 0, 0, TokenFlags.Transferable);
            simulator.EndBlock();

            var token     = simulator.Nexus.GetTokenInfo(nftSymbol);
            var tokenData = new byte[] { 0x1, 0x3, 0x3, 0x7 };

            Assert.IsTrue(nexus.TokenExists(nftSymbol), "Can't find the token symbol");

            // verify nft presence on the sender pre-mint
            var ownerships     = new OwnershipSheet(nftSymbol);
            var ownedTokenList = ownerships.Get(sourceChain.Storage, sender.Address);

            Assert.IsTrue(!ownedTokenList.Any(), "How does the sender already have a CoolToken?");

            // Mint a new CoolToken directly on the sender
            simulator.BeginBlock();
            simulator.GenerateNft(owner, sender.Address, nftSymbol, tokenData, new byte[0]);
            simulator.EndBlock();

            // verify nft presence on the sender post-mint
            ownedTokenList = ownerships.Get(sourceChain.Storage, sender.Address);
            Assert.IsTrue(ownedTokenList.Count() == 1, "How does the sender not have one now?");

            //verify that the present nft is the same we actually tried to create
            var tokenId = ownedTokenList.ElementAt(0);
            var nft     = nexus.GetNFT(nftSymbol, tokenId);

            Assert.IsTrue(nft.ROM.SequenceEqual(tokenData) || nft.RAM.SequenceEqual(tokenData),
                          "And why is this NFT different than expected? Not the same data");

            // verify nft presence on the receiver pre-transfer
            ownedTokenList = ownerships.Get(targetChain.Storage, receiver.Address);
            Assert.IsTrue(!ownedTokenList.Any(), "How does the receiver already have a CoolToken?");

            var extraFee = UnitConversion.ToBigInteger(0.001m, Nexus.FuelTokenDecimals);

            // transfer that nft from sender to receiver
            simulator.BeginBlock();
            simulator.GenerateSideChainSend(sender, Nexus.FuelTokenSymbol, sourceChain, receiver.Address, targetChain, smallAmount, extraFee);
            var txA = simulator.GenerateNftSidechainTransfer(sender, receiver.Address, sourceChain, targetChain, nftSymbol, tokenId);

            simulator.EndBlock();

            var blockA = nexus.RootChain.LastBlock;

            // finish the chain transfer
            simulator.BeginBlock();
            simulator.GenerateSideChainSettlement(receiver, nexus.RootChain, targetChain, blockA.Hash);
            Assert.IsTrue(simulator.EndBlock().Any());

            // verify the sender no longer has it
            ownedTokenList = ownerships.Get(sourceChain.Storage, sender.Address);
            Assert.IsTrue(!ownedTokenList.Any(), "How does the sender still have one?");

            // verify nft presence on the receiver post-transfer
            ownedTokenList = ownerships.Get(targetChain.Storage, receiver.Address);
            Assert.IsTrue(ownedTokenList.Count() == 1, "How does the receiver not have one now?");

            //verify that the transfered nft is the same we actually tried to create
            tokenId = ownedTokenList.ElementAt(0);
            nft     = nexus.GetNFT(nftSymbol, tokenId);
            Assert.IsTrue(nft.ROM.SequenceEqual(tokenData) || nft.RAM.SequenceEqual(tokenData),
                          "And why is this NFT different than expected? Not the same data");
        }
예제 #13
0
        public void CumulativeUploadMoreThanAvailable()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var testUser = KeyPair.Generate();

            var accountBalance = MinimumValidStake * 100;

            Transaction tx = null;

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.FuelTokenSymbol, 100000000);
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.StakingTokenSymbol, accountBalance);
            simulator.EndBlock();

            //-----------
            //Perform a valid Stake call for minimum staking amount
            var stakeAmount         = MinimumValidStake;
            var startingSoulBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUser.Address);

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, ProofOfWork.None, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("energy", "Stake", testUser.Address, stakeAmount).
                                                     SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            BigInteger stakedAmount = simulator.Nexus.RootChain.InvokeContract("energy", "GetStake", testUser.Address).AsNumber();

            Assert.IsTrue(stakedAmount == stakeAmount);

            var finalSoulBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUser.Address);

            Assert.IsTrue(stakeAmount == startingSoulBalance - finalSoulBalance);

            //-----------
            //Upload a file: should succeed
            var filename    = "notAVirus.exe";
            var headerSize  = CalculateRequiredSize(filename, 0);
            var contentSize = (long)(stakedAmount / MinimumValidStake * KilobytesPerStake * 1024) - (long)headerSize;
            var content     = new byte[contentSize];

            var contentMerkle = new MerkleTree(content);

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, ProofOfWork.None, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("storage", "UploadFile", testUser.Address, filename, contentSize, contentMerkle, ArchiveFlags.None, new byte[0]).
                                                     SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            var usedSpace = simulator.Nexus.RootChain.InvokeContract("storage", "GetUsedSpace", testUser.Address).AsNumber();

            Assert.IsTrue(usedSpace == contentSize + headerSize);

            var oldSpace = contentSize + headerSize;

            //----------
            //Upload a file: should fail due to exceeding available storage capacity

            filename    = "giftFromTroia.exe";
            headerSize  = CalculateRequiredSize(filename, 0);
            contentSize = (long)(stakedAmount / MinimumValidStake * KilobytesPerStake * 1024) - (long)headerSize;
            content     = new byte[contentSize];

            Assert.ThrowsException <ChainException>(() =>
            {
                contentMerkle = new MerkleTree(content);

                simulator.BeginBlock();
                tx = simulator.GenerateCustomTransaction(testUser, ProofOfWork.None, () =>
                                                         ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                         .CallContract("storage", "UploadFile", testUser.Address, filename, contentSize, contentMerkle, ArchiveFlags.None, new byte[0]).
                                                         SpendGas(testUser.Address).EndScript());
                simulator.EndBlock();
            });

            Assert.IsTrue(usedSpace == oldSpace);
        }
예제 #14
0
        public void SideChainTransferMultipleSteps()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var sourceChain = nexus.RootChain;
            var appsChain   = nexus.FindChainByName("apps");

            var symbol = Nexus.FuelTokenSymbol;
            var token  = nexus.GetTokenInfo(symbol);

            var sender   = KeyPair.Generate();
            var receiver = KeyPair.Generate();

            var originalAmount = UnitConversion.ToBigInteger(10, token.Decimals);
            var sideAmount     = originalAmount / 2;

            Assert.IsTrue(sideAmount > 0);

            var newChainName = "testing";

            // Send from Genesis address to "sender" user
            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, sender.Address, nexus.RootChain, symbol, originalAmount);
            simulator.GenerateChain(owner, appsChain, newChainName);
            simulator.EndBlock();

            var targetChain = nexus.FindChainByName(newChainName);

            // verify test user balance
            var balance = nexus.RootChain.GetTokenBalance(symbol, sender.Address);

            Assert.IsTrue(balance == originalAmount);

            // do a side chain send using test user balance from root to apps chain
            simulator.BeginBlock();
            var txA    = simulator.GenerateSideChainSend(sender, symbol, sourceChain, sender.Address, appsChain, sideAmount, 0);
            var blockA = simulator.EndBlock().FirstOrDefault();

            // finish the chain transfer
            simulator.BeginBlock();
            var txB = simulator.GenerateSideChainSettlement(sender, nexus.RootChain, appsChain, blockA.Hash);

            Assert.IsTrue(simulator.EndBlock().Any());

            // we cant transfer the full side amount due to fees
            // TODO  calculate the proper fee values instead of this
            sideAmount /= 2;
            var extraFree = UnitConversion.ToBigInteger(0.01m, token.Decimals);

            // do another side chain send using test user balance from apps to target chain
            simulator.BeginBlock();
            var txC    = simulator.GenerateSideChainSend(sender, symbol, appsChain, receiver.Address, targetChain, sideAmount, extraFree);
            var blockC = simulator.EndBlock().FirstOrDefault();

            // finish the chain transfer
            simulator.BeginBlock();
            var txD = simulator.GenerateSideChainSettlement(sender, appsChain, targetChain, blockC.Hash);

            Assert.IsTrue(simulator.EndBlock().Any());

            // TODO  verify balances
        }
예제 #15
0
        public void TestMarketContract()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var chain = nexus.RootChain;

            var nftSymbol = "COOL";

            var testUser = KeyPair.Generate();

            // Create the token CoolToken as an NFT
            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, nexus.FuelToken, 1000000);
            simulator.GenerateToken(owner, nftSymbol, "CoolToken", 0, 0, Blockchain.Tokens.TokenFlags.Transferable);
            simulator.EndBlock();

            var token = simulator.Nexus.FindTokenBySymbol(nftSymbol);

            Assert.IsTrue(token != null, "Can't find the token symbol");

            // verify nft presence on the user pre-mint
            var ownedTokenList = chain.GetTokenOwnerships(token).Get(testUser.Address);

            Assert.IsTrue(!ownedTokenList.Any(), "How does the sender already have a CoolToken?");

            var tokenROM = new byte[] { 0x1, 0x3, 0x3, 0x7 };
            var tokenRAM = new byte[] { 0x1, 0x4, 0x4, 0x6 };

            // Mint a new CoolToken directly on the user
            simulator.BeginBlock();
            simulator.GenerateNft(owner, testUser.Address, chain, token, tokenROM, tokenRAM);
            simulator.EndBlock();

            var auctions             = (MarketAuction[])simulator.Nexus.RootChain.InvokeContract("market", "GetAuctions");
            var previousAuctionCount = auctions.Length;

            // verify nft presence on the user post-mint
            ownedTokenList = chain.GetTokenOwnerships(token).Get(testUser.Address);
            Assert.IsTrue(ownedTokenList.Count() == 1, "How does the sender not have one now?");
            var tokenID = ownedTokenList.First();

            var price = 1000;

            Timestamp endDate = Timestamp.Now + TimeSpan.FromDays(2);

            simulator.BeginBlock();
            simulator.GenerateCustomTransaction(testUser, () =>
                                                ScriptUtils.
                                                BeginScript().
                                                AllowGas(testUser.Address, Address.Null, 1, 9999).
                                                CallContract("market", "SellToken", testUser.Address, token.Symbol, Nexus.FuelTokenSymbol, tokenID, price, endDate).
                                                SpendGas(testUser.Address).
                                                EndScript()
                                                );
            simulator.EndBlock();

            auctions = (MarketAuction[])simulator.Nexus.RootChain.InvokeContract("market", "GetAuctions");
            Assert.IsTrue(auctions.Length == 1 + previousAuctionCount, "auction ids missing");

            simulator.BeginBlock();
            simulator.GenerateCustomTransaction(owner, () =>
                                                ScriptUtils.
                                                BeginScript().
                                                AllowGas(owner.Address, Address.Null, 1, 9999).
                                                CallContract("market", "BuyToken", owner.Address, token.Symbol, auctions[previousAuctionCount].TokenID).
                                                SpendGas(owner.Address).
                                                EndScript()
                                                );
            simulator.EndBlock();

            auctions = (MarketAuction[])simulator.Nexus.RootChain.InvokeContract("market", "GetAuctions");
            Assert.IsTrue(auctions.Length == previousAuctionCount, "auction ids should be empty at this point");

            // verify that the nft was really moved
            ownedTokenList = chain.GetTokenOwnerships(token).Get(testUser.Address);
            Assert.IsTrue(ownedTokenList.Count() == 0, "How does the seller still have one?");

            ownedTokenList = chain.GetTokenOwnerships(token).Get(owner.Address);
            Assert.IsTrue(ownedTokenList.Count() == 1, "How does the buyer does not have what he bought?");
        }
예제 #16
0
        public void TransferToAccountName()
        {
            var owner     = KeyPair.Generate();
            var simulator = new ChainSimulator(owner, 1234);

            var nexus  = simulator.Nexus;
            var symbol = Nexus.FuelTokenSymbol;

            Func <KeyPair, string, bool> registerName = (keypair, name) =>
            {
                bool result = true;

                try
                {
                    simulator.BeginBlock();
                    var tx        = simulator.GenerateAccountRegistration(keypair, name);
                    var lastBlock = simulator.EndBlock().FirstOrDefault();

                    if (lastBlock != null)
                    {
                        Assert.IsTrue(tx != null);

                        var evts = lastBlock.GetEventsForTransaction(tx.Hash);
                        Assert.IsTrue(evts.Any(x => x.Kind == Blockchain.Contracts.EventKind.AddressRegister));
                    }
                }
                catch (Exception)
                {
                    result = false;
                }

                return(result);
            };

            var targetName = "hello";
            var testUser   = KeyPair.Generate();
            var token      = nexus.GetTokenInfo(symbol);
            var amount     = UnitConversion.ToBigInteger(10, token.Decimals);

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, symbol, amount);
            simulator.EndBlock();

            Assert.IsTrue(registerName(testUser, targetName));

            // Send from Genesis address to test user
            var transferAmount = 1;

            var initialFuelBalance = simulator.Nexus.RootChain.GetTokenBalance(symbol, testUser.Address);

            simulator.BeginBlock();
            simulator.GenerateCustomTransaction(owner, () =>
                                                ScriptUtils.BeginScript().AllowGas(owner.Address, Address.Null, 1, 9999)
                                                .CallContract("token", "TransferTokens", owner.Address, targetName, token.Symbol, transferAmount)
                                                .SpendGas(owner.Address).EndScript());
            simulator.EndBlock();

            var finalFuelBalance = simulator.Nexus.RootChain.GetTokenBalance(symbol, testUser.Address);

            Assert.IsTrue(finalFuelBalance - initialFuelBalance == transferAmount);
        }
예제 #17
0
        public void MultiSigReceive2Test()
        {
            var owner = KeyPair.Generate();

            var multiAddr = KeyPair.Generate();
            var signee1   = KeyPair.Generate();
            var signee2   = KeyPair.Generate();
            var signee3   = KeyPair.Generate();
            var signee4   = KeyPair.Generate();

            var target = KeyPair.Generate();

            List <KeyPair> signees = new List <KeyPair>()
            {
                signee1, signee2, signee3
            };

            var simulator = new ChainSimulator(owner, 1234);

            var minSignees = 4;

            List <Address> addressList = new List <Address>()
            {
                multiAddr.Address,
                signee1.Address,
                signee2.Address,
                signee3.Address,
                signee4.Address
            };

            MultisigSettings settings = new MultisigSettings
            {
                addressCount = addressList.Count,
                signeeCount  = minSignees,
                addressArray = addressList.ToArray()
            };

            var script = GenerateMultisigScript(settings);

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, multiAddr.Address, simulator.Nexus.RootChain, "KCAL", 100000000);
            simulator.GenerateTransfer(owner, multiAddr.Address, simulator.Nexus.RootChain, "SOUL", 2);

            simulator.GenerateTransfer(owner, target.Address, simulator.Nexus.RootChain, "KCAL", 100000000);
            simulator.GenerateTransfer(owner, target.Address, simulator.Nexus.RootChain, "SOUL", 2);

            simulator.GenerateTransfer(owner, signee1.Address, simulator.Nexus.RootChain, "KCAL", 100000000);
            simulator.GenerateTransfer(owner, signee1.Address, simulator.Nexus.RootChain, "SOUL", 2);

            simulator.GenerateTransfer(owner, signee2.Address, simulator.Nexus.RootChain, "KCAL", 100000000);
            simulator.GenerateTransfer(owner, signee2.Address, simulator.Nexus.RootChain, "SOUL", 2);

            simulator.GenerateTransfer(owner, signee3.Address, simulator.Nexus.RootChain, "KCAL", 100000000);
            simulator.GenerateTransfer(owner, signee3.Address, simulator.Nexus.RootChain, "SOUL", 2);

            // register script
            simulator.GenerateCustomTransaction(multiAddr,
                                                () => ScriptUtils.BeginScript().AllowGas(multiAddr.Address, Address.Null, 1, 9999)
                                                .CallContract("account", "RegisterScript", multiAddr.Address, script).SpendGas(multiAddr.Address)
                                                .EndScript());
            simulator.EndBlock();

            var balance = simulator.Nexus.RootChain.GetTokenBalance("SOUL", multiAddr.Address);

            Assert.IsTrue(balance == 2);

            var accountScript = simulator.Nexus.LookUpAddressScript(multiAddr.Address);

            Assert.IsTrue(accountScript != null && accountScript.Length > 0);

            simulator.BeginBlock();

            // send to multisig address
            simulator.GenerateTransfer(target, multiAddr.Address, simulator.Nexus.RootChain, "SOUL", 1);
            simulator.GenerateTransfer(signee1, multiAddr.Address, simulator.Nexus.RootChain, "SOUL", 1);
            simulator.GenerateTransfer(signee2, multiAddr.Address, simulator.Nexus.RootChain, "SOUL", 1);
            simulator.GenerateTransfer(signee3, multiAddr.Address, simulator.Nexus.RootChain, "SOUL", 1);

            simulator.EndBlock();

            var sourceBalanceSOUL = simulator.Nexus.RootChain.GetTokenBalance("SOUL", multiAddr.Address);

            Console.WriteLine("BALANCE: " + sourceBalanceSOUL);
            Assert.IsTrue(sourceBalanceSOUL == 6);

            var targetBalanceSOUL = simulator.Nexus.RootChain.GetTokenBalance("SOUL", target.Address);

            Assert.IsTrue(targetBalanceSOUL == 1);

            targetBalanceSOUL = simulator.Nexus.RootChain.GetTokenBalance("SOUL", signee1.Address);
            Assert.IsTrue(targetBalanceSOUL == 1);

            targetBalanceSOUL = simulator.Nexus.RootChain.GetTokenBalance("SOUL", signee2.Address);
            Assert.IsTrue(targetBalanceSOUL == 1);
        }
예제 #18
0
        public void AccountRegister()
        {
            var owner     = KeyPair.Generate();
            var simulator = new ChainSimulator(owner, 1234);

            var nexus  = simulator.Nexus;
            var symbol = Nexus.FuelTokenSymbol;

            Func <KeyPair, string, bool> registerName = (keypair, name) =>
            {
                bool result = true;

                try
                {
                    simulator.BeginBlock();
                    var tx        = simulator.GenerateAccountRegistration(keypair, name);
                    var lastBlock = simulator.EndBlock().FirstOrDefault();

                    if (lastBlock != null)
                    {
                        Assert.IsTrue(tx != null);

                        var evts = lastBlock.GetEventsForTransaction(tx.Hash);
                        Assert.IsTrue(evts.Any(x => x.Kind == Blockchain.Contracts.EventKind.AddressRegister));
                    }
                }
                catch (Exception)
                {
                    result = false;
                }

                return(result);
            };

            var testUser = KeyPair.Generate();

            var token  = nexus.GetTokenInfo(symbol);
            var amount = UnitConversion.ToBigInteger(10, token.Decimals);

            // Send from Genesis address to test user
            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, symbol, amount);
            simulator.EndBlock();

            // verify test user balance
            var balance = nexus.RootChain.GetTokenBalance(symbol, testUser.Address);

            Assert.IsTrue(balance == amount);

            var targetName = "hello";

            Assert.IsTrue(targetName == targetName.ToLower());

            Assert.IsFalse(registerName(testUser, targetName.Substring(3)));
            Assert.IsFalse(registerName(testUser, targetName.ToUpper()));
            Assert.IsFalse(registerName(testUser, targetName + "!"));
            Assert.IsTrue(registerName(testUser, targetName));

            var currentName = nexus.LookUpAddress(testUser.Address);

            Assert.IsTrue(currentName == targetName);

            var someAddress = nexus.LookUpName(targetName);

            Assert.IsTrue(someAddress == testUser.Address);

            Assert.IsFalse(registerName(testUser, "other"));
        }
예제 #19
0
        public void NftTransfer()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var chain = nexus.RootChain;

            var nftKey    = KeyPair.Generate();
            var nftSymbol = "COOL";
            var nftName   = "CoolToken";

            var sender   = KeyPair.Generate();
            var receiver = KeyPair.Generate();

            // Send some SOUL to the test user (required for gas used in "transfer" transaction)
            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, sender.Address, chain, simulator.Nexus.FuelToken, UnitConversion.ToBigInteger(1, Nexus.FuelTokenDecimals));
            simulator.EndBlock();

            // Create the token CoolToken as an NFT
            simulator.BeginBlock();
            simulator.GenerateToken(owner, nftSymbol, nftName, 0, 0, Blockchain.Tokens.TokenFlags.None);
            simulator.EndBlock();

            var token     = simulator.Nexus.FindTokenBySymbol(nftSymbol);
            var tokenData = new byte[] { 0x1, 0x3, 0x3, 0x7 };

            Assert.IsTrue(token != null, "Can't find the token symbol");

            // verify nft presence on the sender pre-mint
            var ownedTokenList = chain.GetTokenOwnerships(token).Get(sender.Address);

            Assert.IsTrue(!ownedTokenList.Any(), "How does the sender already have a CoolToken?");

            // Mint a new CoolToken directly on the sender
            simulator.BeginBlock();
            simulator.GenerateNft(owner, sender.Address, chain, token, tokenData, new byte[0]);
            simulator.EndBlock();

            // verify nft presence on the sender post-mint
            ownedTokenList = chain.GetTokenOwnerships(token).Get(sender.Address);
            Assert.IsTrue(ownedTokenList.Count() == 1, "How does the sender not have one now?");

            //verify that the present nft is the same we actually tried to create
            var tokenId = ownedTokenList.ElementAt(0);
            var nft     = nexus.GetNFT(token, tokenId);

            Assert.IsTrue(nft.ROM.SequenceEqual(tokenData) || nft.RAM.SequenceEqual(tokenData),
                          "And why is this NFT different than expected? Not the same data");

            // verify nft presence on the receiver pre-transfer
            ownedTokenList = chain.GetTokenOwnerships(token).Get(receiver.Address);
            Assert.IsTrue(!ownedTokenList.Any(), "How does the receiver already have a CoolToken?");

            // transfer that nft from sender to receiver
            simulator.BeginBlock();
            var txA = simulator.GenerateNftTransfer(sender, receiver.Address, chain, token, tokenId);

            simulator.EndBlock();

            // verify nft presence on the receiver post-transfer
            ownedTokenList = chain.GetTokenOwnerships(token).Get(receiver.Address);
            Assert.IsTrue(ownedTokenList.Count() == 1, "How does the receiver not have one now?");

            //verify that the transfered nft is the same we actually tried to create
            tokenId = ownedTokenList.ElementAt(0);
            nft     = nexus.GetNFT(token, tokenId);
            Assert.IsTrue(nft.ROM.SequenceEqual(tokenData) || nft.RAM.SequenceEqual(tokenData),
                          "And why is this NFT different than expected? Not the same data");
        }
예제 #20
0
        public void MultiSigFail3Test()
        {
            var owner     = KeyPair.Generate();
            var multiAddr = KeyPair.Generate();

            var signee1 = KeyPair.Generate();
            var signee2 = KeyPair.Generate();

            var target = KeyPair.Generate();

            List <KeyPair> signees = new List <KeyPair>()
            {
                signee1, signee2
            };

            var simulator  = new ChainSimulator(owner, 1234);
            var minSignees = 4;

            List <Address> addressList = new List <Address>()
            {
                multiAddr.Address,
                signee1.Address,
                signee2.Address
            };

            MultisigSettings settings = new MultisigSettings
            {
                addressCount = addressList.Count,
                signeeCount  = minSignees,
                addressArray = addressList.ToArray()
            };

            var script = GenerateMultisigScript(settings);

            simulator.BeginBlock();

            simulator.GenerateTransfer(owner, multiAddr.Address, simulator.Nexus.RootChain, "KCAL", 100000000);
            simulator.GenerateTransfer(owner, multiAddr.Address, simulator.Nexus.RootChain, "SOUL", 2);

            // register script
            simulator.GenerateCustomTransaction(multiAddr,
                                                () => ScriptUtils.BeginScript().AllowGas(multiAddr.Address, Address.Null, 1, 9999)
                                                .CallContract("account", "RegisterScript", multiAddr.Address, script).SpendGas(multiAddr.Address)
                                                .EndScript());
            simulator.EndBlock();

            var balance = simulator.Nexus.RootChain.GetTokenBalance("SOUL", multiAddr.Address);

            Assert.IsTrue(balance == 2);

            var accountScript = simulator.Nexus.LookUpAddressScript(multiAddr.Address);

            Assert.IsTrue(accountScript != null && accountScript.Length > 0);

            Assert.ThrowsException <Exception>(() =>
            {
                simulator.BeginBlock();
                // do multisig tx --> will fail with Phantasma.VM.VMDebugException: transfer failed
                simulator.GenerateTransfer(multiAddr, target.Address, simulator.Nexus.RootChain, "SOUL", 1, signees);
                simulator.EndBlock();
            });

            var sourceBalanceSOUL = simulator.Nexus.RootChain.GetTokenBalance("SOUL", multiAddr.Address);

            Console.WriteLine("SOUL: " + sourceBalanceSOUL);
            Assert.IsTrue(sourceBalanceSOUL == 2);

            var targetBalanceKCAL = simulator.Nexus.RootChain.GetTokenBalance("KCAL", target.Address);

            Assert.IsTrue(targetBalanceKCAL == 0);

            var targetBalanceSOUL = simulator.Nexus.RootChain.GetTokenBalance("SOUL", target.Address);

            Assert.IsTrue(targetBalanceSOUL == 0);
        }
예제 #21
0
        public void TestNachoPurchase()
        {
            var owner     = KeyPair.Generate();
            var simulator = new ChainSimulator(owner, 1234);

            var tokenSupply = ToBigInteger(69931640.63m, NACHO_TOKEN_DECIMALS);

            simulator.BeginBlock();
            simulator.GenerateToken(owner, NACHO_SYMBOL, NACHO_SYMBOL, Nexus.PlatformName, Hash.FromString(NACHO_SYMBOL), tokenSupply, NACHO_TOKEN_DECIMALS, Fungible | Transferable | Finite | Divisible);
            simulator.MintTokens(owner, owner.Address, NACHO_SYMBOL, tokenSupply);
            simulator.EndBlock();

            var buyer    = KeyPair.Generate();
            var receiver = KeyPair.Generate();
            var nexus    = simulator.Nexus;

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, buyer.Address, nexus.RootChain, FuelTokenSymbol, 100000000);
            simulator.MintTokens(owner, owner.Address, FiatTokenSymbol,
                                 new BigInteger("1000000000000000000000000000000000000000000000000", 10) * GetUnitValue(FiatTokenDecimals));
            //simulator.GenerateTransfer(owner, buyer.Address, nexus.RootChain, Nexus.FiatTokenSymbol, 1000000 * UnitConversion.GetUnitValue(Nexus.FiatTokenDecimals));
            simulator.EndBlock();

            var ownerFiat = simulator.Nexus.RootChain.GetTokenBalance(Nexus.FiatTokenSymbol, owner.Address);

            decimal requiredMoney = 0;

            for (int stage = 0; stage < stageCount; stage++)
            {
                for (int milestone = 1; milestone <= milestoneCount; milestone++)
                {
                    decimal milestoneTokens = stageTokenAmount[stage] * milestone / 10m;
                    milestoneTokens = Math.Round(milestoneTokens, 2, AwayFromZero);

                    decimal milestoneTokensPerUsd = stageTokensPerUsd[stage] * tokenDecreaseFactor[stage];
                    milestoneTokensPerUsd = Math.Round(milestoneTokensPerUsd, 3, AwayFromZero);

                    requiredMoney += milestoneTokens / milestoneTokensPerUsd;

                    Assert.IsTrue(requiredMoney >= 500, "unexpected order size: not enough for 40% bonus");

                    requiredMoney = requiredMoney / 1.4m;

                    var bigintMoney = ToBigInteger(requiredMoney, FiatTokenDecimals);

                    simulator.BeginBlock();
                    simulator.GenerateTransfer(owner, buyer.Address, nexus.RootChain, FiatTokenSymbol, bigintMoney);
                    simulator.EndBlock();

                    var initialNachos = simulator.Nexus.RootChain.GetTokenBalance(NACHO_SYMBOL, receiver.Address);
                    var initialFiat   = simulator.Nexus.RootChain.GetTokenBalance(Nexus.FiatTokenSymbol, receiver.Address);

                    simulator.BeginBlock();
                    simulator.GenerateCustomTransaction(buyer, ProofOfWork.None, () =>
                                                        ScriptUtils.BeginScript().AllowGas(buyer.Address, Address.Null, 1, 9999)
                                                        .CallContract("nacho", "BuyInApp", buyer.Address, FiatTokenSymbol, bigintMoney).
                                                        SpendGas(buyer.Address).EndScript());
                    simulator.EndBlock();

                    var finalNachos = simulator.Nexus.RootChain.GetTokenBalance(NACHO_SYMBOL, receiver.Address);
                    var finalFiat   = simulator.Nexus.RootChain.GetTokenBalance(Nexus.FiatTokenSymbol, receiver.Address);

                    var milestoneTokensBigInt = ToBigInteger(milestoneTokens, NACHO_TOKEN_DECIMALS);

                    Assert.IsTrue(finalNachos == initialNachos + milestoneTokensBigInt);
                    Assert.IsTrue(finalFiat == initialFiat - bigintMoney);
                }
            }
        }
예제 #22
0
        public void UnstakeWithStoredFilesFailure()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var testUser = KeyPair.Generate();

            var accountBalance = BaseEnergyRatioDivisor * 100;

            Transaction tx = null;

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.FuelTokenSymbol, 100000000);
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.StakingTokenSymbol, accountBalance);
            simulator.EndBlock();

            //-----------
            //Perform a valid Stake call for minimum staking amount
            var stakedAmount        = BaseEnergyRatioDivisor;
            var startingSoulBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUser.Address);

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("energy", "Stake", testUser.Address, stakedAmount).
                                                     SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            //-----------
            //Upload a file
            var filename = "notAVirus.exe";

            var headerSize  = CalculateRequiredSize(filename, 0);
            var contentSize = (long)(stakedAmount * KilobytesPerStake * 1024) - (long)headerSize;
            var content     = new byte[contentSize];

            var contentMerkle = new MerkleTree(content);

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("storage", "UploadFile", testUser.Address, filename, contentSize, contentMerkle, ArchiveFlags.None, new byte[0]).
                                                     SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            var usedSpace = (BigInteger)simulator.Nexus.RootChain.InvokeContract("storage", "GetUsedSpace", testUser.Address);

            Assert.IsTrue(usedSpace == contentSize);

            //-----------
            //Time skip 1 day
            simulator.TimeSkipDays(1);

            //-----------
            //Try to unstake everything: should fail due to files still existing for this user
            var initialStakedAmount = (BigInteger)simulator.Nexus.RootChain.InvokeContract("energy", "GetStake", testUser.Address);
            var stakeReduction      = initialStakedAmount - BaseEnergyRatioDivisor;

            startingSoulBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUser.Address);

            Assert.ThrowsException <Exception>(() =>
            {
                simulator.BeginBlock();
                simulator.GenerateCustomTransaction(testUser, () =>
                                                    ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                    .CallContract("energy", "Unstake", testUser.Address, stakeReduction).
                                                    SpendGas(testUser.Address).EndScript());
                simulator.EndBlock();
            });

            var finalStakedAmount = (BigInteger)simulator.Nexus.RootChain.InvokeContract("energy", "GetStake", testUser.Address);

            Assert.IsTrue(initialStakedAmount == finalStakedAmount);

            usedSpace = (BigInteger)simulator.Nexus.RootChain.InvokeContract("storage", "GetUsedSpace", testUser.Address);
        }
예제 #23
0
        public void SingleUploadSuccess()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var testUser = KeyPair.Generate();

            var accountBalance = MinimumValidStake * 5;

            Transaction tx = null;

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.FuelTokenSymbol, 100000000);
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.StakingTokenSymbol, accountBalance);
            simulator.EndBlock();

            //-----------
            //Perform a valid Stake call for minimum staking amount
            var stakeAmount         = accountBalance / 2;
            var startingSoulBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUser.Address);

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("energy", "Stake", testUser.Address, stakeAmount).
                                                     SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            BigInteger stakedAmount = (BigInteger)simulator.Nexus.RootChain.InvokeContract("energy", "GetStake", testUser.Address);

            Assert.IsTrue(stakedAmount == stakeAmount);

            var finalSoulBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUser.Address);

            Assert.IsTrue(stakeAmount == startingSoulBalance - finalSoulBalance);

            //-----------
            //Upload a file: should succeed
            var filename    = "notAVirus.exe";
            var headerSize  = CalculateRequiredSize(filename, 0);
            var contentSize = (long)(((UnitConversion.ToDecimal(stakedAmount, Nexus.StakingTokenDecimals)) * KilobytesPerStake) * 1024) - (long)headerSize;
            var content     = new byte[contentSize];
            var rnd         = new Random();

            for (int i = 0; i < content.Length; i++)
            {
                content[i] = (byte)rnd.Next();
            }

            var contentMerkle = new MerkleTree(content);

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("storage", "UploadFile", testUser.Address, filename, contentSize, contentMerkle, ArchiveFlags.None, new byte[0]).
                                                     SpendGas(testUser.Address).EndScript());

            //System.IO.File.WriteAllText(@"c:\code\bug_vm.txt", string.Join('\n', new VM.Disassembler(tx.Script).Instructions));
            simulator.EndBlock();

            var usedSpace = (BigInteger)simulator.Nexus.RootChain.InvokeContract("storage", "GetUsedSpace", testUser.Address);

            Assert.IsTrue(usedSpace == 0);

            Assert.IsTrue(simulator.Nexus.ArchiveExists(contentMerkle.Root));
            var archive = simulator.Nexus.FindArchive(contentMerkle.Root);

            for (int i = 0; i < archive.BlockCount; i++)
            {
                int ofs          = (int)(i * Archive.BlockSize);
                var blockContent = content.Skip(ofs).Take((int)Archive.BlockSize).ToArray();
                simulator.Nexus.WriteArchiveBlock(archive, blockContent, i);
            }
        }
예제 #24
0
        public void NoGasTestSideChainTransfer()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var sourceChain = nexus.RootChain;
            var targetChain = nexus.FindChainByName("privacy");

            var symbol = Nexus.FuelTokenSymbol;
            var token  = nexus.GetTokenInfo(symbol);

            var sender   = KeyPair.Generate();
            var receiver = KeyPair.Generate();

            var originalAmount = UnitConversion.ToBigInteger(10, token.Decimals);
            var sideAmount     = originalAmount / 2;

            Assert.IsTrue(sideAmount > 0);

            // Send from Genesis address to "sender" user
            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, sender.Address, nexus.RootChain, symbol, originalAmount);
            simulator.EndBlock();

            // verify test user balance
            var balance = nexus.RootChain.GetTokenBalance(symbol, sender.Address);

            Assert.IsTrue(balance == originalAmount);

            Transaction txA = null, txB = null;

            try
            {
                // do a side chain send using test user balance from root to account chain
                simulator.BeginBlock();
                txA = simulator.GenerateSideChainSend(sender, symbol, sourceChain, receiver.Address, targetChain,
                                                      originalAmount, 1);
                simulator.EndBlock();
            }
            catch (Exception e)
            {
                Assert.IsNotNull(e);
            }

            try
            {
                var blockA = nexus.RootChain.LastBlock;

                // finish the chain transfer
                simulator.BeginBlock();
                txB = simulator.GenerateSideChainSettlement(sender, nexus.RootChain, targetChain, blockA.Hash);
                Assert.IsTrue(simulator.EndBlock().Any());
            }
            catch (Exception e)
            {
                Assert.IsNotNull(e);
            }


            // verify balances, receiver should have 0 balance
            balance = targetChain.GetTokenBalance(symbol, receiver.Address);
            Assert.IsTrue(balance == 0);
        }
예제 #25
0
        public CLI(string[] args)
        {
            var culture = new CultureInfo("en-US");

            CultureInfo.DefaultThreadCurrentCulture = culture;

            var seeds = new List <string>();

            var settings = new Arguments(args);

            /*
             * for (int i = 0; i < 20; i++)
             * {
             *  var k = KeyPair.Generate();
             *  Console.WriteLine(k.ToWIF() + " => " + k.Address.Text);
             * }*/

            var useGUI = settings.GetBool("gui.enabled", true);

            if (useGUI)
            {
                gui    = new ConsoleGUI();
                logger = gui;
            }
            else
            {
                gui    = null;
                logger = new ConsoleLogger();
            }

            string mode = settings.GetString("node.mode", "validator");

            bool hasRPC  = settings.GetBool("rpc.enabled", false);
            bool hasREST = settings.GetBool("rest.enabled", false);

            string wif = settings.GetString("node.wif");

            var nexusName = settings.GetString("nexus.name", "simnet");

            switch (mode)
            {
            case "sender":
                string host               = settings.GetString("sender.host");
                int    threadCount        = settings.GetInt("sender.threads", 8);
                int    addressesPerSender = settings.GetInt("sender.addressCount", 100);
                RunSender(wif, host, threadCount, addressesPerSender);
                Console.WriteLine("Sender finished operations.");
                return;

            case "validator": break;

            default:
            {
                logger.Error("Unknown mode: " + mode);
                return;
            }
            }

            int defaultPort = 0;

            for (int i = 0; i < validatorWIFs.Length; i++)
            {
                if (validatorWIFs[i] == wif)
                {
                    defaultPort = (7073 + i);
                }
            }

            if (defaultPort == 0)
            {
                defaultPort = (7073 + validatorWIFs.Length);
            }

            int port = settings.GetInt("node.port", defaultPort);
            var defaultStoragePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "/Storage";
            var storagePath        = settings.GetString("storage.path", defaultStoragePath);

            storagePath = storagePath.Replace("\\", "/");
            if (!storagePath.EndsWith('/'))
            {
                storagePath += '/';
            }

            var storageFix = settings.GetBool("storage.fix", false);

            // TODO remove this later
            if (storageFix)
            {
                if (Directory.Exists(storagePath))
                {
                    logger.Warning("Storage fix enabled... Cleaning up all storage...");
                    var di = new DirectoryInfo(storagePath);
                    foreach (FileInfo file in di.EnumerateFiles())
                    {
                        file.Delete();
                    }
                }
            }

            logger.Message("Storage path: " + storagePath);

            var node_keys = KeyPair.FromWIF(wif);

            nexus = new Nexus(logger, (name) => new BasicDiskStore(storagePath + name + ".txt"));

            bool bootstrap = false;

            if (wif == validatorWIFs[0])
            {
                if (!nexus.Ready)
                {
                    logger.Debug("Boostraping nexus...");
                    bootstrap = true;
                    if (!nexus.CreateGenesisBlock(nexusName, node_keys, Timestamp.Now))
                    {
                        throw new ChainException("Genesis block failure");
                    }

                    logger.Debug("Genesis block created: " + nexus.GenesisHash);
                }
            }
            else
            {
                //nexus = new Nexus(nexusName, genesisAddress, logger);
                nexus = new Nexus(logger);
                seeds.Add("127.0.0.1:7073");
            }

            // TODO this should be later optional to enable
            nexus.AddPlugin(new ChainAddressesPlugin());
            nexus.AddPlugin(new TokenTransactionsPlugin());
            nexus.AddPlugin(new AddressTransactionsPlugin());
            nexus.AddPlugin(new UnclaimedTransactionsPlugin());

            running = true;

            // mempool setup
            int blockTime = settings.GetInt("node.blocktime", Mempool.MinimumBlockTime);

            this.mempool = new Mempool(node_keys, nexus, blockTime, ReadFromOracle);
            mempool.Start(ThreadPriority.AboveNormal);

            mempool.OnTransactionFailed += Mempool_OnTransactionFailed;

            api = new NexusAPI(nexus, mempool);

            // RPC setup
            if (hasRPC)
            {
                int rpcPort = settings.GetInt("rpc.port", 7077);

                logger.Message($"RPC server listening on port {rpcPort}...");
                var rpcServer = new RPCServer(api, "/rpc", rpcPort, (level, text) => WebLogMapper("rpc", level, text));
                rpcServer.Start(ThreadPriority.AboveNormal);
            }

            // REST setup
            if (hasREST)
            {
                int restPort = settings.GetInt("rest.port", 7078);

                logger.Message($"REST server listening on port {restPort}...");
                var restServer = new RESTServer(api, "/api", restPort, (level, text) => WebLogMapper("rest", level, text));
                restServer.Start(ThreadPriority.AboveNormal);
            }


            cryptoCompareAPIKey = settings.GetString("cryptocompare.apikey", "");
            if (!string.IsNullOrEmpty(cryptoCompareAPIKey))
            {
                logger.Message($"CryptoCompare API enabled...");
            }

            // node setup
            this.node = new Node(nexus, mempool, node_keys, port, seeds, logger);
            node.Start();

            if (gui != null)
            {
                int pluginPeriod = settings.GetInt("plugin.refresh", 1); // in seconds
                RegisterPlugin(new TPSPlugin(logger, pluginPeriod));
                RegisterPlugin(new RAMPlugin(logger, pluginPeriod));
                RegisterPlugin(new MempoolPlugin(mempool, logger, pluginPeriod));
            }

            Console.CancelKeyPress += delegate {
                Terminate();
            };

            var dispatcher = new CommandDispatcher();

            SetupCommands(dispatcher);

            bool useSimulator = settings.GetBool("simulator.enabled", false);

            if (useSimulator && bootstrap)
            {
                new Thread(() =>
                {
                    logger.Message("Initializing simulator...");
                    var simulator = new ChainSimulator(this.nexus, node_keys, 1234);

                    logger.Message("Bootstrapping validators");
                    simulator.BeginBlock();
                    for (int i = 1; i < validatorWIFs.Length; i++)
                    {
                        simulator.GenerateTransfer(node_keys, Address.FromWIF(validatorWIFs[i]), this.nexus.RootChain, Nexus.StakingTokenSymbol, UnitConversion.ToBigInteger(50000, Nexus.StakingTokenDecimals));
                    }
                    simulator.EndBlock();

                    for (int i = 0; i < 3; i++)
                    {
                        logger.Message("Generating sim block #" + i);
                        simulator.GenerateRandomBlock();
                    }

                    NachoServer.InitNachoServer(nexus, simulator, node_keys, logger);
                    MakeReady(dispatcher);
                }).Start();
            }
            else
            {
                MakeReady(dispatcher);
            }

            this.Run();
        }
예제 #26
0
        public void UploadDuplicateFilename()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var testUser = KeyPair.Generate();

            var accountBalance = BaseEnergyRatioDivisor * 100;

            Transaction tx = null;

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.FuelTokenSymbol, 100000000);
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.StakingTokenSymbol, accountBalance);
            simulator.EndBlock();

            //-----------
            //Perform a valid Stake call
            var stakeAmount         = MinimumValidStake * 2;
            var startingSoulBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUser.Address);

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("energy", "Stake", testUser.Address, stakeAmount).
                                                     SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            BigInteger stakedAmount = (BigInteger)simulator.Nexus.RootChain.InvokeContract("energy", "GetStake", testUser.Address);

            Assert.IsTrue(stakedAmount == stakeAmount);

            var finalSoulBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUser.Address);

            Assert.IsTrue(stakeAmount == startingSoulBalance - finalSoulBalance);

            //-----------
            //Upload a file: should succeed
            var filename    = "notAVirus.exe";
            var headerSize  = CalculateRequiredSize(filename, 0);
            var contentSize = (long)(stakeAmount * KilobytesPerStake * 1024 / 2) - (long)headerSize;
            var content     = new byte[contentSize];

            var contentMerkle = new MerkleTree(content);

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("storage", "UploadFile", testUser.Address, filename, contentSize, contentMerkle, ArchiveFlags.None, new byte[0]).
                                                     SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            var usedSpace = (BigInteger)simulator.Nexus.RootChain.InvokeContract("storage", "GetUsedSpace", testUser.Address);

            Assert.IsTrue(usedSpace == contentSize + headerSize);

            var oldSpace = contentSize + headerSize;

            //----------
            //Upload a file with the same name: should fail
            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("storage", "UploadFile", testUser.Address, filename, contentSize, content, ArchiveFlags.None, new byte[0]).
                                                     SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            Assert.IsTrue(usedSpace == oldSpace);
        }
예제 #27
0
        public void ReduceAvailableSpace()
        {
            var owner = KeyPair.Generate();

            var simulator = new ChainSimulator(owner, 1234);
            var nexus     = simulator.Nexus;

            var testUser = KeyPair.Generate();

            var accountBalance = BaseEnergyRatioDivisor * 100;

            Transaction tx = null;

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.FuelTokenSymbol, 100000000);
            simulator.GenerateTransfer(owner, testUser.Address, nexus.RootChain, Nexus.StakingTokenSymbol, accountBalance);
            simulator.EndBlock();

            //-----------
            //Perform a valid Stake call for minimum staking amount
            var stakedAmount        = BaseEnergyRatioDivisor * 5;
            var startingSoulBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUser.Address);

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("energy", "Stake", testUser.Address, stakedAmount).
                                                     SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            //-----------
            //Upload a file
            var filename = "notAVirus.exe";

            var headerSize  = (BigInteger)simulator.Nexus.RootChain.InvokeContract("storage", "CalculateRequiredSize", filename, 0);
            var contentSize = (long)(stakedAmount * KilobytesPerStake * 1024 / 5) - (long)headerSize;
            var content     = new byte[contentSize];

            simulator.BeginBlock();
            tx = simulator.GenerateCustomTransaction(testUser, () =>
                                                     ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                     .CallContract("storage", "UploadFile", testUser.Address, filename, contentSize, content, ArchiveFlags.None).
                                                     SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            var usedSpace = (BigInteger)simulator.Nexus.RootChain.InvokeContract("storage", "GetUsedSpace", testUser.Address);

            Assert.IsTrue(usedSpace == contentSize);

            //-----------
            //Time skip 1 day
            simulator.TimeSkipDays(1);

            //-----------
            //Try partial unstake: should succeed
            var initialStakedAmount = (BigInteger)simulator.Nexus.RootChain.InvokeContract("energy", "GetStake", testUser.Address);
            var stakeReduction      = stakedAmount / 5;

            startingSoulBalance = simulator.Nexus.RootChain.GetTokenBalance(Nexus.StakingTokenSymbol, testUser.Address);

            simulator.BeginBlock();
            simulator.GenerateCustomTransaction(testUser, () =>
                                                ScriptUtils.BeginScript().AllowGas(testUser.Address, Address.Null, 1, 9999)
                                                .CallContract("energy", "Unstake", testUser.Address, stakeReduction).
                                                SpendGas(testUser.Address).EndScript());
            simulator.EndBlock();

            var finalStakedAmount = (BigInteger)simulator.Nexus.RootChain.InvokeContract("energy", "GetStake", testUser.Address);

            Assert.IsTrue(finalStakedAmount == 0);
        }