Esempio n. 1
0
        //public NexusSimulator(PhantasmaKeys ownerKey, int seed, Logger logger = null) : this(new Nexus("simnet", null, null), ownerKey, seed, logger)
        //{
        //    this.Nexus.SetOracleReader(new OracleSimulator(this.Nexus));
        //}

        public NexusSimulator(Nexus nexus, PhantasmaKeys ownerKey, int seed, Logger logger = null)
        {
            this.Logger = logger != null ? logger : new DummyLogger();

            _owner     = ownerKey;
            this.Nexus = nexus;

            CurrentTime = new DateTime(2018, 8, 26, 0, 0, 0, DateTimeKind.Utc);

            if (!Nexus.HasGenesis)
            {
                if (!Nexus.CreateGenesisBlock(_owner, CurrentTime, 5))
                {
                    throw new ChainException("Genesis block failure");
                }
            }
            else
            {
                var lastBlockHash = Nexus.RootChain.GetLastBlockHash();
                var lastBlock     = Nexus.RootChain.GetBlockByHash(lastBlockHash);
                CurrentTime = new Timestamp(lastBlock.Timestamp.Value + 1);
                DateTime.SpecifyKind(CurrentTime, DateTimeKind.Utc);
            }

            _rnd = new Random(seed);
            _keys.Add(_owner);

            var oneFuel      = UnitConversion.ToBigInteger(1, DomainSettings.FuelTokenDecimals);
            var token        = Nexus.GetTokenInfo(Nexus.RootStorage, DomainSettings.FuelTokenSymbol);
            var localBalance = Nexus.RootChain.GetTokenBalance(Nexus.RootStorage, token, _owner.Address);

            if (localBalance < oneFuel)
            {
                throw new Exception("Funds missing oops");
            }

            var neoPlatform = Pay.Chains.NeoWallet.NeoPlatform;
            var neoKeys     = InteropUtils.GenerateInteropKeys(_owner, Nexus.GetGenesisHash(Nexus.RootStorage), neoPlatform);
            var neoText     = Phantasma.Neo.Core.NeoKeys.FromWIF(neoKeys.ToWIF()).Address;
            var neoAddress  = Phantasma.Pay.Chains.NeoWallet.EncodeAddress(neoText);

            var ethPlatform = Pay.Chains.EthereumWallet.EthereumPlatform;
            var ethKeys     = InteropUtils.GenerateInteropKeys(_owner, Nexus.GetGenesisHash(Nexus.RootStorage), ethPlatform);
            var ethText     = Phantasma.Ethereum.EthereumKey.FromWIF(ethKeys.ToWIF()).Address;
            var ethAddress  = Phantasma.Pay.Chains.EthereumWallet.EncodeAddress(ethText);

            // only create all this stuff once
            if (!nexus.PlatformExists(nexus.RootStorage, neoPlatform))
            {
                /*BeginBlock();
                 * GenerateCustomTransaction(_owner, ProofOfWork.None, () =>
                 * {
                 *  return new ScriptBuilder().AllowGas(_owner.Address, Address.Null, 1, 99999).
                 *  CallContract(NativeContractKind.Governance, nameof(GovernanceContract.SetValue), Nexus.NexusProtocolVersionTag, 3).
                 *  SpendGas(_owner.Address).
                 *  EndScript();
                 * });
                 * EndBlock();*/

                BeginBlock();
                GenerateCustomTransaction(_owner, 0, () => new ScriptBuilder().AllowGas(_owner.Address, Address.Null, MinimumFee, 9999).
                                          CallInterop("Nexus.CreatePlatform", _owner.Address, neoPlatform, neoText, neoAddress, "GAS").
                                          CallInterop("Nexus.CreatePlatform", _owner.Address, ethPlatform, ethText, ethAddress, "ETH").
                                          SpendGas(_owner.Address).EndScript());

                var orgFunding = UnitConversion.ToBigInteger(1863626, DomainSettings.StakingTokenDecimals);
                var orgScript  = new byte[0];
                var orgID      = DomainSettings.PhantomForceOrganizationName;
                var orgAddress = Address.FromHash(orgID);

                GenerateCustomTransaction(_owner, ProofOfWork.None, () =>
                {
                    return(new ScriptBuilder().AllowGas(_owner.Address, Address.Null, 1, 99999).
                           CallInterop("Nexus.CreateOrganization", _owner.Address, orgID, "Phantom Force", orgScript).
                           CallInterop("Organization.AddMember", _owner.Address, orgID, _owner.Address).
                           TransferTokens(DomainSettings.StakingTokenSymbol, _owner.Address, orgAddress, orgFunding).
                           CallContract(NativeContractKind.Swap, nameof(SwapContract.SwapFee), orgAddress, DomainSettings.StakingTokenSymbol, 500000).
                           CallContract(NativeContractKind.Stake, nameof(StakeContract.Stake), orgAddress, orgFunding - (5000)).
                           SpendGas(_owner.Address).
                           EndScript());
                });
                EndBlock();

                BeginBlock();
                var communitySupply = 100000;
                GenerateToken(_owner, "MKNI", "Mankini Token", UnitConversion.ToBigInteger(communitySupply, 0), 0, TokenFlags.Fungible | TokenFlags.Transferable | TokenFlags.Finite);
                MintTokens(_owner, _owner.Address, "MKNI", communitySupply);
                EndBlock();

                //TODO add SOUL/KCAL on ethereum, removed for now because hash is not fixed yet
                //BeginBlock();
                //GenerateCustomTransaction(_owner, ProofOfWork.Minimal, () =>
                //{
                //    return new ScriptBuilder().AllowGas(_owner.Address, Address.Null, 1, 99999).
                //    CallInterop("Nexus.SetTokenPlatformHash", "SOUL", ethPlatform, Hash.FromUnpaddedHex("53d5bdb2c8797218f8a0e11e997c4ab84f0b40ce")). // eth ropsten testnet hash
                //    CallInterop("Nexus.SetTokenPlatformHash", "KCAL", ethPlatform, Hash.FromUnpaddedHex("67B132A32E7A3c4Ba7dEbedeFf6290351483008f")). // eth ropsten testnet hash
                //    SpendGas(_owner.Address).
                //    EndScript();
                //});
                //EndBlock();
            }

            /*
             * var market = Nexus.FindChainByName("market");
             * var nftSales = new List<KeyValuePair<KeyPair, BigInteger>>();
             *
             * BeginBlock();
             * for (int i = 1; i < 7; i++)
             * {
             *  BigInteger ID = i + 100;
             *  TokenContent info;
             *  try
             *  {
             *      info = Nexus.GetNFT(nachoSymbol, ID);
             *  }
             *  catch
             *  {
             *      continue;
             *  }
             *
             *  var chain = Nexus.FindChainByAddress(info.CurrentChain);
             *  if (chain == null)
             *  {
             *      continue;
             *  }
             *
             *  var nftOwner = chain.GetTokenOwner(nachoSymbol, ID);
             *
             *  if (nftOwner == Address.Null)
             *  {
             *      continue;
             *  }
             *
             *  foreach (var key in _keys)
             *  {
             *      if (key.Address == nftOwner)
             *      {
             *          nftSales.Add(new KeyValuePair<KeyPair, BigInteger>(key, ID));
             *          // send some gas to the sellers
             *          GenerateTransfer(_owner, key.Address, Nexus.RootChain, Nexus.FuelTokenSymbol, UnitConversion.ToBigInteger(0.01m, Nexus.FuelTokenDecimals));
             *      }
             *  }
             * }
             *
             * EndBlock();
             *
             * BeginBlock();
             * foreach (var sale in nftSales)
             * {
             *  // TODO this later should be the market chain instead of root
             *  GenerateNftSale(sale.Key, Nexus.RootChain, nachoSymbol, sale.Value, UnitConversion.ToBigInteger(100 + 5 * _rnd.Next() % 50, Nexus.FuelTokenDecimals));
             * }
             * EndBlock();
             */
        }
Esempio n. 2
0
        public void GenerateRandomBlock(Mempool mempool = null)
        {
            BeginBlock();

            int transferCount = 1 + _rnd.Next() % 10;
            int tries         = 0;

            while (tries < 10000)
            {
                if (transactions.Count >= transferCount)
                {
                    break;
                }

                tries++;
                var source = _keys[_rnd.Next() % _keys.Count];

                if (usedAddresses.Contains(source.Address))
                {
                    continue;
                }

                var prevTxCount = transactions.Count;

                var sourceChain = Nexus.RootChain;
                var fee         = 9999;

                string tokenSymbol;

                switch (_rnd.Next() % 4)
                {
                case 1: tokenSymbol = DomainSettings.FiatTokenSymbol; break;

                //case 2: token = Nexus.FuelTokenSymbol; break;
                default: tokenSymbol = DomainSettings.StakingTokenSymbol; break;
                }

                switch (_rnd.Next() % 7)
                {
                /*
                 * // side-chain send
                 * case 1:
                 *  {
                 *      var sourceChainList = Nexus.Chains.ToArray();
                 *      sourceChain = Nexus.GetChainByName( sourceChainList[_rnd.Next() % sourceChainList.Length]);
                 *
                 *      var targetChainList = Nexus.Chains.Select(x => Nexus.GetChainByName(x)).Where(x => Nexus.GetParentChainByName(x.Name) == sourceChain.Name || Nexus.GetParentChainByName(sourceChain.Name) == x.Name).ToArray();
                 *      var targetChain = targetChainList[_rnd.Next() % targetChainList.Length];
                 *
                 *      var total = UnitConversion.ToBigInteger(1 + _rnd.Next() % 100, DomainSettings.FuelTokenDecimals);
                 *
                 *      var tokenBalance = sourceChain.GetTokenBalance(sourceChain.Storage, tokenSymbol, source.Address);
                 *      var fuelBalance = sourceChain.GetTokenBalance(sourceChain.Storage, DomainSettings.FuelTokenSymbol, source.Address);
                 *
                 *      var expectedTotal = total;
                 *      if (tokenSymbol == DomainSettings.FuelTokenSymbol)
                 *      {
                 *          expectedTotal += fee;
                 *      }
                 *
                 *      var sideFee = 0;
                 *      if (tokenSymbol != DomainSettings.FuelTokenSymbol)
                 *      {
                 *          sideFee = fee;
                 *      }
                 *
                 *      if (tokenBalance > expectedTotal && fuelBalance > fee + sideFee)
                 *      {
                 *          Logger.Debug($"Rnd.SideChainSend: {total} {tokenSymbol} from {source.Address}");
                 *          GenerateSideChainSend(source, tokenSymbol, sourceChain, source.Address, targetChain, total, sideFee);
                 *      }
                 *      break;
                 *  }
                 *
                 * // side-chain receive
                 * case 2:
                 *  {
                 *      if (_pendingBlocks.Any())
                 *      {
                 *          var pendingBlock = _pendingBlocks.First();
                 *
                 *          if (mempool == null || Nexus.GetConfirmationsOfHash(pendingBlock.hash) > 0)
                 *          {
                 *
                 *              var balance = pendingBlock.destChain.GetTokenBalance(pendingBlock.destChain.Storage, pendingBlock.tokenSymbol, source.Address);
                 *              if (balance > 0)
                 *              {
                 *                  Logger.Message($"...Settling {pendingBlock.sourceChain.Name}=>{pendingBlock.destChain.Name}: {pendingBlock.hash}");
                 *                  GenerateSideChainSettlement(source, pendingBlock.sourceChain, pendingBlock.destChain, pendingBlock.hash);
                 *              }
                 *          }
                 *      }
                 *
                 *      break;
                 *  }
                 */
                /*
                 * // stable claim
                 * case 3:
                 * {
                 *  sourceChain = bankChain;
                 *  tokenSymbol = Nexus.FuelTokenSymbol;
                 *
                 *  var balance = sourceChain.GetTokenBalance(tokenSymbol, source.Address);
                 *
                 *  var total = UnitConversion.ToBigInteger(1 + _rnd.Next() % 100, Nexus.FuelTokenDecimals - 1);
                 *
                 *  if (balance > total + fee)
                 *  {
                 *      Logger.Debug($"Rnd.StableClaim: {total} {tokenSymbol} from {source.Address}");
                 *      GenerateStableClaim(source, sourceChain, total);
                 *  }
                 *
                 *  break;
                 * }
                 *
                 * // stable redeem
                 * case 4:
                 * {
                 *  sourceChain = bankChain;
                 *  tokenSymbol = Nexus.FiatTokenSymbol;
                 *
                 *  var tokenBalance = sourceChain.GetTokenBalance(tokenSymbol, source.Address);
                 *  var fuelBalance = sourceChain.GetTokenBalance(Nexus.FuelTokenSymbol, source.Address);
                 *
                 *  var rate = (BigInteger) bankChain.InvokeContract("bank", "GetRate", Nexus.FuelTokenSymbol);
                 *  var total = tokenBalance / 10;
                 *  if (total >= rate && fuelBalance > fee)
                 *  {
                 *      Logger.Debug($"Rnd.StableRedeem: {total} {tokenSymbol} from {source.Address}");
                 *      GenerateStableRedeem(source, sourceChain, total);
                 *  }
                 *
                 *  break;
                 * }*/

                // name register
                case 5:
                {
                    sourceChain = this.Nexus.RootChain;
                    tokenSymbol = DomainSettings.FuelTokenSymbol;

                    var token = Nexus.GetTokenInfo(Nexus.RootStorage, tokenSymbol);

                    var balance = sourceChain.GetTokenBalance(sourceChain.Storage, token, source.Address);
                    if (balance > fee + AccountContract.RegistrationCost && !pendingNames.Contains(source.Address))
                    {
                        var randomName = accountNames[_rnd.Next() % accountNames.Length];

                        switch (_rnd.Next() % 10)
                        {
                        case 1:
                        case 2:
                            randomName += (_rnd.Next() % 10).ToString();
                            break;

                        case 3:
                        case 4:
                        case 5:
                            randomName += (10 + _rnd.Next() % 90).ToString();
                            break;

                        case 6:
                            randomName += (100 + _rnd.Next() % 900).ToString();
                            break;
                        }

                        var currentName = Nexus.RootChain.GetNameFromAddress(Nexus.RootStorage, source.Address);
                        if (currentName == ValidationUtils.ANONYMOUS_NAME)
                        {
                            var lookup = Nexus.LookUpName(Nexus.RootStorage, randomName);
                            if (lookup.IsNull)
                            {
                                Logger.Debug($"Rnd.GenerateAccount: {source.Address} => {randomName}");
                                GenerateAccountRegistration(source, randomName);
                            }
                        }
                    }

                    break;
                }

                // normal transfer
                default:
                {
                    var     temp = _rnd.Next() % 5;
                    Address targetAddress;

                    if ((_keys.Count < 2 || temp == 0) && _keys.Count < 2000)
                    {
                        var key = PhantasmaKeys.Generate();
                        _keys.Add(key);
                        targetAddress = key.Address;
                    }
                    else
                    {
                        targetAddress = _keys[_rnd.Next() % _keys.Count].Address;
                    }

                    if (source.Address != targetAddress)
                    {
                        var total = UnitConversion.ToBigInteger(1 + _rnd.Next() % 100, DomainSettings.FuelTokenDecimals - 1);

                        var token        = Nexus.GetTokenInfo(Nexus.RootStorage, tokenSymbol);
                        var tokenBalance = sourceChain.GetTokenBalance(sourceChain.Storage, token, source.Address);

                        var fuelToken   = Nexus.GetTokenInfo(Nexus.RootStorage, DomainSettings.FuelTokenSymbol);
                        var fuelBalance = sourceChain.GetTokenBalance(sourceChain.Storage, fuelToken, source.Address);

                        var expectedTotal = total;
                        if (tokenSymbol == DomainSettings.FuelTokenSymbol)
                        {
                            expectedTotal += fee;
                        }

                        if (tokenBalance > expectedTotal && fuelBalance > fee)
                        {
                            Logger.Message($"Rnd.Transfer: {total} {tokenSymbol} from {source.Address} to {targetAddress}");
                            GenerateTransfer(source, targetAddress, sourceChain, tokenSymbol, total);
                        }
                    }
                    break;
                }
                }
            }

            if (transactions.Count > 0)
            {
                EndBlock(mempool);
            }
            else
            {
                CancelBlock();
            }
        }
Esempio n. 3
0
        public IEnumerator ECDsaSecP256k1()
        {
            // Eth address: "0x66571c32d77c4852be4c282eb952ba94efbeac20";
            var key = "6f6784731c4e526c97fa6a97b6f22e96f307588c5868bc2c545248bc31207eb1";

            Assert.IsTrue(key.Length == 64);

            var privBytes     = Base16.Decode(key);
            var phantasmaKeys = new PhantasmaKeys(privBytes);

            var wif     = phantasmaKeys.ToWIF();
            var ethKeys = EthereumKey.FromWIF(wif);

            Debug.Log("Eth address: " + ethKeys);

            var pKey = ECCurve.Secp256k1.G * privBytes;
            var ethPublicKeyCompressed = pKey.EncodePoint(true).ToArray();

            Debug.Log("Eth compressed public key: " + Base16.Encode(ethPublicKeyCompressed));
            var ethPublicKeyUncompressed = pKey.EncodePoint(false).Skip(1).ToArray();

            Debug.Log("Eth uncompressed public key: " + Base16.Encode(ethPublicKeyUncompressed));

            var msgBytes  = Encoding.ASCII.GetBytes("Phantasma");
            var signature = ethKeys.Sign(msgBytes, (message, prikey, pubkey) =>
            {
                return(Phantasma.Neo.Utils.CryptoUtils.Sign(message, prikey, pubkey, Phantasma.Cryptography.ECC.ECDsaCurve.Secp256k1));
            });

            var ecdsaSignature      = (ECDsaSignature)signature;
            var signatureSerialized = signature.Serialize(); // signature.ToByteArray() gives same result

            Debug.Log("\nSignature (RAW concatenated r & s, hex):\n" + Base16.Encode(ecdsaSignature.Bytes));
            // Curve byte: ECDsaCurve enum: Secp256r1 = 0, Secp256k1 = 1.
            // Following is the format we use for signature:
            Debug.Log("\nSignature (curve byte + signature length + concatenated r & s, hex):\n" + Base16.Encode(signatureSerialized));

            var signatureDEREncoded = ethKeys.Sign(msgBytes, (message, prikey, pubkey) =>
            {
                return(Phantasma.Neo.Utils.CryptoUtils.Sign(message, prikey, pubkey, Phantasma.Cryptography.ECC.ECDsaCurve.Secp256k1, Neo.Utils.CryptoUtils.SignatureFormat.DEREncoded));
            });

            var ecdsaSignatureDEREncoded = (ECDsaSignature)signatureDEREncoded;

            Debug.Log("\nSignature (RAW DER-encoded, hex):\n" + Base16.Encode(ecdsaSignatureDEREncoded.Bytes));
            Debug.Log("\nSignature (curve byte + signature length + DER-encoded, hex):\n" + Base16.Encode(signatureDEREncoded.Serialize()));

            // Since ECDsaSignature class not working for us,
            // we use signature .Bytes directly to verify it with Bouncy Castle.
            // Verifying concatenated signature / compressed Eth public key.
            Assert.IsTrue(Phantasma.Neo.Utils.CryptoUtils.Verify(msgBytes, ecdsaSignature.Bytes, ethPublicKeyCompressed, ECDsaCurve.Secp256k1));

            // Verifying concatenated signature / uncompressed Eth public key.
            // Not working with Bouncy Castle.
            // Assert.IsTrue(Phantasma.Neo.Utils.CryptoUtils.Verify(msgBytes, ecdsaSignature.Bytes, ethPublicKeyUncompressed, ECDsaCurve.Secp256k1));

            // Verifying DER signature.
            Assert.IsTrue(Phantasma.Neo.Utils.CryptoUtils.Verify(msgBytes, ecdsaSignatureDEREncoded.Bytes, ethPublicKeyCompressed, ECDsaCurve.Secp256k1, Neo.Utils.CryptoUtils.SignatureFormat.DEREncoded));

            // This method we cannot use, it gives "System.NotImplementedException : The method or operation is not implemented."
            // exception in Unity, because Unity does not fully support .NET cryptography.
            // Assert.IsTrue(((ECDsaSignature)signature).Verify(msgBytes, Address.FromKey(ethKeys)));

            // Failes for same reason: "System.NotImplementedException".
            // Assert.IsTrue(CryptoExtensions.VerifySignatureECDsa(msgBytes, signatureSerialized, ethPublicKeyCompressed, ECDsaCurve.Secp256k1));

            yield return(null);
        }
Esempio n. 4
0
        public Transaction GenerateToken(PhantasmaKeys owner, string symbol, string name, BigInteger totalSupply,
                                         int decimals, TokenFlags flags, byte[] tokenScript = null, Dictionary <string, int> labels = null, IEnumerable <ContractMethod> customMethods = null)
        {
            var version = Nexus.GetGovernanceValue(Nexus.RootStorage, Nexus.NexusProtocolVersionTag);

            if (labels == null)
            {
                labels = new Dictionary <string, int>();
            }

            if (tokenScript == null)
            {
                // small script that restricts minting of tokens to transactions where the owner is a witness
                var      addressStr = Base16.Encode(owner.Address.ToByteArray());
                string[] scriptString;

                if (version >= 4)
                {
                    scriptString = new string[] {
                        $"alias r3, $result",
                        $"alias r4, $owner",
                        $"@{AccountTrigger.OnMint}: nop",
                        $"load $owner 0x{addressStr}",
                        "push $owner",
                        "extcall \"Address()\"",
                        "extcall \"Runtime.IsWitness\"",
                        "pop $result",
                        $"jmpif $result, @end",
                        $"load r0 \"invalid witness\"",
                        $"throw r0",

                        $"@end: ret"
                    };
                }
                else
                {
                    scriptString = new string[] {
                        $"alias r1, $triggerMint",
                        $"alias r2, $currentTrigger",
                        $"alias r3, $result",
                        $"alias r4, $owner",

                        $@"load $triggerMint, ""{AccountTrigger.OnMint}""",
                        $"pop $currentTrigger",

                        $"equal $triggerMint, $currentTrigger, $result",
                        $"jmpif $result, @mintHandler",
                        $"jmp @end",

                        $"@mintHandler: nop",
                        $"load $owner 0x{addressStr}",
                        "push $owner",
                        "extcall \"Address()\"",
                        "extcall \"Runtime.IsWitness\"",
                        "pop $result",
                        $"jmpif $result, @end",
                        $"load r0 \"invalid witness\"",
                        $"throw r0",

                        $"@end: ret"
                    };
                }
                DebugInfo debugInfo;
                tokenScript = AssemblerUtils.BuildScript(scriptString, "GenerateToken", out debugInfo, out labels);
            }

            var sb = ScriptUtils.
                     BeginScript().
                     AllowGas(owner.Address, Address.Null, MinimumFee, 9999);

            if (version >= 4)
            {
                var triggerMap = new Dictionary <AccountTrigger, int>();

                var onMintLabel = AccountTrigger.OnMint.ToString();
                if (labels.ContainsKey(onMintLabel))
                {
                    triggerMap[AccountTrigger.OnMint] = labels[onMintLabel];
                }

                var methods = AccountContract.GetTriggersForABI(triggerMap);

                if (customMethods != null)
                {
                    methods = methods.Concat(customMethods);
                }

                var abi      = new ContractInterface(methods, Enumerable.Empty <ContractEvent>());
                var abiBytes = abi.ToByteArray();

                sb.CallInterop("Nexus.CreateToken", owner.Address, symbol, name, totalSupply, decimals, flags, tokenScript, abiBytes);
            }
            else
            {
                sb.CallInterop("Nexus.CreateToken", owner.Address, symbol, name, totalSupply, decimals, flags, tokenScript);
            }

            if (!flags.HasFlag(TokenFlags.Fungible))
            {
                ContractInterface nftABI;
                byte[]            nftScript;
                NFTUtils.GenerateNFTDummyScript(symbol, name, name, "http://simulator/nft/*", "http://simulator/img/*", out nftScript, out nftABI);
                sb.CallInterop("Nexus.CreateTokenSeries", owner.Address, symbol, new BigInteger(0), totalSupply, TokenSeriesMode.Unique, nftScript, nftABI.ToByteArray());
            }

            sb.SpendGas(owner.Address);

            var script = sb.EndScript();

            var tx = MakeTransaction(owner, ProofOfWork.Minimal, Nexus.RootChain, script);

            return(tx);
        }
Esempio n. 5
0
        static void Main(string[] args)
        {
            /*var obj = Serialization.Unserialize<VMObject>(Base16.Decode("0821204DBC2216A0EA109AA3436D23A67F381AE98282C040E5F117CDFDA80108733D04"));
             * var hash = obj.AsInterop<Hash>();
             * Console.WriteLine(hash);*/

            Console.Write($"Enter nexus name: ");
            nexusName = Console.ReadLine();

            Console.Write($"Enter WIF for signing transaction: ");
            var wif = Console.ReadLine();

            signerKeys = PhantasmaKeys.FromWIF(wif);

            Console.WriteLine("Select operation: ");
            Console.WriteLine("0 - Exit");
            Console.WriteLine("1 - DAO Transfer");
            Console.WriteLine("2 - Create token");
            Console.WriteLine("3 - Mint tokens");
            Console.WriteLine("4 - Create sale");
            Console.WriteLine("5 - Whitelist sale address");

            var str = Console.ReadLine();

            int option;

            if (!int.TryParse(str, out option))
            {
                Console.WriteLine("Invalid option...");
                return;
            }

            byte[] script;

            switch (option)
            {
            case 0:
                return;

            case 1:
                script = GenDAOTransfer();
                break;

            case 2:
                script = GenCreateToken();
                break;

            case 3:
                script = GenMintToken();
                break;

            case 4:
                script = GenCreateSale();
                break;

            case 5:
                script = GenWhitelist();
                break;

            case 6:
            {
                var sb = new ScriptBuilder().AllowGas(signerKeys.Address, Address.Null, 100000, 99999);

                //sb.CallContract(NativeContractKind.Sale, nameof(SaleContract.EditSalePrice), Hash.Parse("043D730801A8FDCD17F1E540C08282E91A387FA6236D43A39A10EAA01622BC4D"), 4);
                sb.CallInterop("Organization.Kill", signerKeys.Address, "exchange_pot");

                script = sb.SpendGas(signerKeys.Address).
                         EndScript();
                break;
            }

            default:
                Console.WriteLine("Unsupported option...");
                return;
            }

            if (script == null)
            {
                Console.WriteLine("Transaction generation failed...");
                return;
            }

            var expiration = new Timestamp(Timestamp.Now.Value + 1000);
            var tx         = new Transaction(nexusName, "main", script, expiration, "TXSNDER1.0");

            tx.Mine(ProofOfWork.Minimal);
            tx.Sign(signerKeys);

            var rawTx = tx.ToByteArray(true);

            var hexRawTx = Base16.Encode(rawTx);


            Console.Write("Node REST URL: ");
            var url = Console.ReadLine();

            if (!url.StartsWith("http"))
            {
                url = "http://" + url;
            }

            // check for port
            if (!url.Replace("http://", "").Contains(":"))
            {
                var defaultPort = 7078;
                Console.WriteLine("No port specified, using defaul port " + defaultPort);
                url += ":" + defaultPort;
            }

            var baseUrl = url;

            url = baseUrl + "/api/sendRawTransaction/" + hexRawTx;

            if (url.Length > 2040)
            {
                Console.WriteLine("Script is too big");
                return;
            }

            Hash txHash;

            using (var wb = new WebClient())
            {
                var response = wb.DownloadString(url);

                Console.WriteLine(response);

                if (response.StartsWith("\""))
                {
                    response = response.Substring(1, response.Length - 2);
                }

                if (!Hash.TryParse(response, out txHash))
                {
                    Console.WriteLine("Failed...");
                    return;
                }
            }

            Console.WriteLine("Confirming...");
            Thread.Sleep(1000 * 20);

            url = baseUrl + "/api/getTransaction/" + txHash.ToString();
            using (var wb = new WebClient())
            {
                var response = wb.DownloadString(url);

                Console.WriteLine(response);
            }

            Console.WriteLine("Finished.");
            Console.ReadLine();
        }
Esempio n. 6
0
 public EthereumWallet(PhantasmaKeys keys) : base(keys)
 {
 }
Esempio n. 7
0
        private void SenderSpawn(int ID, PhantasmaKeys masterKeys, string nexusName, string host, BigInteger initialAmount, int addressesListSize)
        {
            Throw.IfNull(logger, nameof(logger));

            Thread.CurrentThread.IsBackground = true;

            BigInteger fee = 9999; // TODO calculate the real fee

            BigInteger amount = initialAmount;

            var tcp  = new TcpClient("localhost", 7073);
            var peer = new TCPPeer(tcp.Client);

            var peerKey = PhantasmaKeys.Generate();

            logger.Message($"#{ID}: Connecting to peer: {host} with address {peerKey.Address.Text}");
            var request = new RequestMessage(RequestKind.None, nexusName, peerKey.Address);

            request.Sign(peerKey);
            peer.Send(request);

            int batchCount = 0;

            var rpc = new JSONRPC_Client();

            {
                logger.Message($"#{ID}: Sending funds to address {peerKey.Address.Text}");
                var hash = SendTransfer(rpc, logger, nexusName, host, masterKeys, peerKey.Address, initialAmount);
                if (hash == Hash.Null)
                {
                    logger.Error($"#{ID}:Stopping, fund transfer failed");
                    return;
                }

                if (!ConfirmTransaction(rpc, logger, host, hash))
                {
                    logger.Error($"#{ID}:Stopping, fund confirmation failed");
                    return;
                }
            }

            logger.Message($"#{ID}: Beginning send mode");
            bool returnPhase = false;
            var  txs         = new List <Transaction>();

            var addressList = new List <PhantasmaKeys>();
            int waveCount   = 0;

            while (true)
            {
                bool shouldConfirm;

                try
                {
                    txs.Clear();


                    if (returnPhase)
                    {
                        foreach (var target in addressList)
                        {
                            var script = ScriptUtils.BeginScript().AllowGas(target.Address, Address.Null, 1, 9999).TransferTokens("SOUL", target.Address, peerKey.Address, 1).SpendGas(target.Address).EndScript();
                            var tx     = new Transaction(nexusName, "main", script, Timestamp.Now + TimeSpan.FromMinutes(30));
                            tx.Sign(target);
                            txs.Add(tx);
                        }

                        addressList.Clear();
                        returnPhase   = false;
                        waveCount     = 0;
                        shouldConfirm = true;
                    }
                    else
                    {
                        amount -= fee * 2 * addressesListSize;
                        if (amount <= 0)
                        {
                            break;
                        }

                        for (int j = 0; j < addressesListSize; j++)
                        {
                            var target = PhantasmaKeys.Generate();
                            addressList.Add(target);

                            var script = ScriptUtils.BeginScript().AllowGas(peerKey.Address, Address.Null, 1, 9999).TransferTokens("SOUL", peerKey.Address, target.Address, 1 + fee).SpendGas(peerKey.Address).EndScript();
                            var tx     = new Transaction(nexusName, "main", script, Timestamp.Now + TimeSpan.FromMinutes(30));
                            tx.Sign(peerKey);
                            txs.Add(tx);
                        }

                        waveCount++;
                        if (waveCount > 10)
                        {
                            returnPhase   = true;
                            shouldConfirm = true;
                        }
                        else
                        {
                            shouldConfirm = false;
                        }
                    }

                    returnPhase = !returnPhase;

                    var msg = new MempoolAddMessage(peerKey.Address, txs);
                    msg.Sign(peerKey);
                    peer.Send(msg);
                }
                catch (Exception e)
                {
                    logger.Error($"#{ID}:Fatal error : {e}");
                    return;
                }

                if (txs.Any())
                {
                    if (shouldConfirm)
                    {
                        var confirmation = ConfirmTransaction(rpc, logger, host, txs.Last().Hash);
                        if (!confirmation)
                        {
                            logger.Error($"#{ID}:Confirmation failed, aborting...");
                        }
                    }
                    else
                    {
                        Thread.Sleep(500);
                    }

                    batchCount++;
                    logger.Message($"#{ID}:Sent {txs.Count} transactions (batch #{batchCount})");
                }
                else
                {
                    logger.Message($"#{ID}: No transactions left");
                    return;
                }
            }

            logger.Message($"#{ID}: Thread ran out of funds");
        }
Esempio n. 8
0
        private Hash SendTransfer(string host, PhantasmaKeys from, Address to, BigInteger amount, string tokenSymbol = "SOUL")
        {
            var script = ScriptUtils.BeginScript().AllowGas(from.Address, Address.Null, 1, 9999).TransferTokens(tokenSymbol, from.Address, to, amount).SpendGas(from.Address).EndScript();

            return(SendTransaction(host, from, script));
        }
Esempio n. 9
0
        public StorageChangeSetContext ProcessBlock(Block block, IEnumerable <Transaction> transactions, BigInteger minimumFee, out Transaction inflationTx, PhantasmaKeys signingKeys)
        {
            if (!block.Validator.IsUser)
            {
                throw new BlockGenerationException($"block validator must be user address");
            }

            Block lastBlock;

            using (var m = new ProfileMarker("GetLastBlock"))
            {
                var lastBlockHash = GetLastBlockHash();
                lastBlock = GetBlockByHash(lastBlockHash);
            }

            if (lastBlock != null)
            {
                if (lastBlock.Height != block.Height - 1)
                {
                    throw new BlockGenerationException($"height of block should be {lastBlock.Height + 1}");
                }

                if (block.PreviousHash != lastBlock.Hash)
                {
                    throw new BlockGenerationException($"previous hash should be {lastBlock.PreviousHash}");
                }

                if (block.Timestamp < lastBlock.Timestamp)
                {
                    throw new BlockGenerationException($"timestamp of block {block.Timestamp} should be greater than {lastBlock.Timestamp}");
                }
            }

            var inputHashes = new HashSet <Hash>(transactions.Select(x => x.Hash).Distinct());

            var txBlockMap = new StorageMap(TxBlockHashMapTag, this.Storage);

            var diff = transactions.Count() - inputHashes.Count;

            if (diff > 0)
            {
                var temp = new HashSet <Hash>();
                foreach (var tx in transactions)
                {
                    if (temp.Contains(tx.Hash))
                    {
                        throw new DuplicatedTransactionException(tx.Hash, $"transaction {tx.Hash} appears more than once in the block being minted");
                    }
                    else
                    if (txBlockMap.ContainsKey <Hash>(tx.Hash))
                    {
                        var previousBlockHash = txBlockMap.Get <Hash, Hash>(tx.Hash);
                        throw new DuplicatedTransactionException(tx.Hash, $"transaction {tx.Hash} already added to previous block {previousBlockHash}");
                    }
                    else
                    {
                        temp.Add(tx.Hash);
                    }
                }
            }

            foreach (var hash in block.TransactionHashes)
            {
                if (!inputHashes.Contains(hash))
                {
                    throw new BlockGenerationException($"missing in inputs transaction with hash {hash}");
                }
            }

            var outputHashes = new HashSet <Hash>(block.TransactionHashes);

            foreach (var tx in transactions)
            {
                if (!outputHashes.Contains(tx.Hash))
                {
                    throw new BlockGenerationException($"missing in outputs transaction with hash {tx.Hash}");
                }
            }

            foreach (var tx in transactions)
            {
                if (!tx.IsValid(this))
                {
#if DEBUG
                    tx.IsValid(this);
#endif
                    throw new InvalidTransactionException(tx.Hash, $"invalid transaction with hash {tx.Hash}");
                }
            }

            var oracle = Nexus.GetOracleReader();

            block.CleanUp();

            var changeSet = ProcessTransactions(block, transactions, oracle, minimumFee, out inflationTx, signingKeys);

            Address expectedValidator;
            using (var m = new ProfileMarker("GetValidator"))
                expectedValidator = Nexus.HasGenesis ? GetValidator(Nexus.RootStorage, block.Timestamp) : Nexus.GetGenesisAddress(Nexus.RootStorage);

            var migrationFound  = false;
            var migratedAddress = Address.Null;
            foreach (var hash in outputHashes)
            {
                if (migrationFound)
                {
                    break;
                }

                var events = block.GetEventsForTransaction(hash);
                foreach (var evt in events)
                {
                    if (evt.Kind == EventKind.AddressMigration && evt.Contract == "validator")
                    {
                        var oldAddress = evt.GetContent <Address>();
                        if (oldAddress == expectedValidator)
                        {
                            migratedAddress = evt.Address;
                            migrationFound  = true;
                            break;
                        }
                    }
                }
            }

            if (block.Validator != expectedValidator && !expectedValidator.IsNull)
            {
                if (migrationFound && migratedAddress == block.Validator)
                {
                    expectedValidator = migratedAddress;
                }
                else
                {
                    throw new BlockGenerationException($"unexpected validator {block.Validator}, expected {expectedValidator}");
                }
            }

            if (oracle.Entries.Any())
            {
                block.MergeOracle(oracle);
                oracle.Clear();
            }

            return(changeSet);
        }
Esempio n. 10
0
        private static Hash SendTransfer(JSONRPC_Client rpc, Logger logger, string nexusName, string host, PhantasmaKeys from, Address to, BigInteger amount)
        {
            Throw.IfNull(rpc, nameof(rpc));
            Throw.IfNull(logger, nameof(logger));

            var script = ScriptUtils.BeginScript().AllowGas(from.Address, Address.Null, 1, 9999).TransferTokens("SOUL", from.Address, to, amount).SpendGas(from.Address).EndScript();

            var tx = new Transaction(nexusName, "main", script, Timestamp.Now + TimeSpan.FromMinutes(30));

            tx.Sign(from);

            var bytes = tx.ToByteArray(true);

            //log.Debug("RAW: " + Base16.Encode(bytes));

            var response = rpc.SendRequest(logger, host, "sendRawTransaction", Base16.Encode(bytes));

            if (response == null)
            {
                logger.Error($"Error sending {amount} {DomainSettings.FuelTokenSymbol} from {from.Address} to {to}...");
                return(Hash.Null);
            }

            if (response.HasNode("error"))
            {
                var error = response.GetString("error");
                logger.Error("Error: " + error);
                return(Hash.Null);
            }

            var hash = response.Value;

            return(Hash.Parse(hash));
        }
Esempio n. 11
0
        // signingKeys should be null if the block should not be modified
        public StorageChangeSetContext ProcessTransactions(Block block, IEnumerable <Transaction> transactions
                                                           , OracleReader oracle, BigInteger minimumFee, out Transaction inflationTx, PhantasmaKeys signingKeys)
        {
            bool allowModify = signingKeys != null;

            if (allowModify)
            {
                block.CleanUp();
            }

            var changeSet = new StorageChangeSetContext(this.Storage);

            transactions = ProcessPendingTasks(block, oracle, minimumFee, changeSet, allowModify).Concat(transactions);

            int txIndex = 0;

            foreach (var tx in transactions)
            {
                VMObject vmResult;
                try
                {
                    using (var m = new ProfileMarker("ExecuteTransaction"))
                    {
                        if (ExecuteTransaction(txIndex, tx, tx.Script, block.Validator, block.Timestamp, changeSet, block.Notify, oracle, ChainTask.Null, minimumFee, out vmResult, allowModify))
                        {
                            if (vmResult != null)
                            {
                                if (allowModify)
                                {
                                    var resultBytes = Serialization.Serialize(vmResult);
                                    block.SetResultForHash(tx.Hash, resultBytes);
                                }
                            }
                        }
                        else
                        {
                            throw new InvalidTransactionException(tx.Hash, "script execution failed");
                        }
                    }
                }
                catch (Exception e)
                {
                    e = e.ExpandInnerExceptions();

                    // log original exception, throwing it again kills the call stack!
                    Log.Error($"Exception while transactions of block {block.Height}: " + e);

                    if (tx == null)
                    {
                        throw new BlockGenerationException(e.Message);
                    }

                    throw new InvalidTransactionException(tx.Hash, e.Message);
                }

                txIndex++;
            }

            inflationTx = null;

            if (this.IsRoot && allowModify)
            {
                var inflationReady = NativeContract.LoadFieldFromStorage <bool>(changeSet, NativeContractKind.Gas, nameof(GasContract._inflationReady));

                if (inflationReady)
                {
                    if (!(block.Height >= 242942) && !(block.Height <= 242944))
                    {
                        Console.WriteLine("do inflation now");
                        var script = new ScriptBuilder()
                                     .AllowGas(block.Validator, Address.Null, minimumFee, 999999)
                                     .CallContract(NativeContractKind.Gas, nameof(GasContract.ApplyInflation), block.Validator)
                                     .SpendGas(block.Validator)
                                     .EndScript();

                        var transaction = new Transaction(this.Nexus.Name, this.Name, script, block.Timestamp.Value + 1, "SYSTEM");

                        transaction.Sign(signingKeys);

                        VMObject vmResult;

                        if (!ExecuteTransaction(-1, transaction, transaction.Script, block.Validator, block.Timestamp, changeSet, block.Notify, oracle, ChainTask.Null, minimumFee, out vmResult, allowModify))
                        {
                            throw new ChainException("failed to execute inflation transaction");
                        }

                        inflationTx = transaction;
                        block.AddTransactionHash(transaction.Hash);
                    }
                }
            }

            if (block.Protocol > DomainSettings.LatestKnownProtocol)
            {
                throw new BlockGenerationException($"unexpected protocol number {block.Protocol}, maybe software update required?");
            }

            // Only check protocol version if block is created on this node, no need to check if it's a non validator node.
            if (allowModify)
            {
                var expectedProtocol = Nexus.GetGovernanceValue(Nexus.RootStorage, Nexus.NexusProtocolVersionTag);
                if (block.Protocol != expectedProtocol)
                {
                    throw new BlockGenerationException($"invalid protocol number {block.Protocol}, expected protocol {expectedProtocol}");
                }

                using (var m = new ProfileMarker("CloseBlock"))
                {
                    CloseBlock(block, changeSet);
                }
            }

            return(changeSet);
        }
Esempio n. 12
0
        public static void Upload(string txIdentifier, PhantasmaKeys source, NexusAPI api, string[] args)
        {
            if (args.Length != 1)
            {
                throw new CommandException("Expected args: file_path");
            }

            var filePath = args[0];

            if (!File.Exists(filePath))
            {
                throw new CommandException("File does not exist");
            }

            var fileContent   = File.ReadAllBytes(filePath);
            var contentMerkle = new MerkleTree(fileContent);

            var fileName = Path.GetFileName(filePath);

            var script = ScriptUtils.BeginScript().
                         AllowGas(source.Address, Address.Null, 1, 9999).
                         CallContract("storage", "UploadFile", source.Address, fileName, fileContent.Length, contentMerkle, new byte[0]).
                         SpendGas(source.Address).
                         EndScript();
            var tx = new Transaction(api.Nexus.Name, "main", script, Timestamp.Now + TimeSpan.FromMinutes(5), txIdentifier);

            tx.Sign(source);
            var rawTx = tx.ToByteArray(true);

            logger.Message($"Uploading {fileName}...");
            try
            {
                api.SendRawTransaction(Base16.Encode(rawTx));
            }
            catch (Exception e)
            {
                throw new CommandException(e.Message);
            }

            Thread.Sleep(3000);
            var hash = tx.Hash.ToString();

            do
            {
                try
                {
                    var result = api.GetTransaction(hash);
                }
                catch (Exception e)
                {
                    throw new CommandException(e.Message);
                }

                /*if (result is ErrorResult)
                 * {
                 *  var temp = (ErrorResult)result;
                 *  if (temp.error.Contains("pending"))
                 *  {
                 *      Thread.Sleep(1000);
                 *  }
                 *  else
                 *  {
                 *      throw new CommandException(temp.error);
                 *  }
                 * }
                 * else*/
                {
                    break;
                }
            } while (true);

            var archiveHash = contentMerkle.Root.ToString();
            var archive     = (ArchiveResult)api.GetArchive(archiveHash);

            for (int i = 0; i < archive.blockCount; i++)
            {
                var ofs          = (int)(i * Archive.BlockSize);
                var blockContent = fileContent.Skip(ofs).Take((int)Archive.BlockSize).ToArray();

                logger.Message($"Writing block {i+1} out of {archive.blockCount}");
                api.WriteArchive(archiveHash, i, Base16.Encode(blockContent));
            }

            logger.Message($"File uploaded successfully!");
        }
Esempio n. 13
0
 protected override string DeriveAddress(PhantasmaKeys keys)
 {
     return(keys.Address.Text);
 }
Esempio n. 14
0
        public void TestAutoSendAddress()
        {
            var test = CreateAPI();

            var simulator  = test.simulator;
            var owner      = test.owner;
            var testUser   = PhantasmaKeys.Generate();
            var autoSender = PhantasmaKeys.Generate();
            var receiver   = PhantasmaKeys.Generate();
            var node       = PhantasmaKeys.FromWIF(nodeWIF);
            var nexus      = simulator.Nexus;
            var api        = test.api;

            var symbol = DomainSettings.StakingTokenSymbol;

            var senderAddressStr    = Base16.Encode(autoSender.Address.ToByteArray());
            var receivingAddressStr = Base16.Encode(receiver.Address.ToByteArray());

            string[] scriptString = new string[]
            {
                $"alias r1, $triggerReceive",
                $"alias r2, $currentTrigger",
                $"alias r3, $comparisonResult",

                $@"load $triggerReceive, ""{AccountTrigger.OnReceive}""",
                $"pop $currentTrigger",

                $"equal $triggerReceive, $currentTrigger, $comparisonResult",
                $"jmpif $comparisonResult, @receiveHandler",

                $"jmp @end",

                $"@receiveHandler: nop",

                $"alias r4, $tokenContract",
                $"alias r5, $sourceAddress",
                $"alias r6, $targetAddress",
                $"alias r7, $receivedAmount",
                $"alias r8, $symbol",
                $"alias r9, $methodName",

                $"pop $symbol",
                $"pop $sourceAddress",
                $"pop $receivedAmount",

                $"load r11 0x{receivingAddressStr}",
                $"push r11",
                $@"extcall ""Address()""",
                $"pop $targetAddress",

                $@"load $methodName, ""TransferTokens""",

                $"push $receivedAmount",
                $"push $symbol",
                $"push $targetAddress",
                $"push $sourceAddress",
                $@"push $methodName",

                //switch to token contract
                $@"load r12, ""token""",
                $"ctx r12, $tokenContract",
                $"switch $tokenContract",

                $"@end: ret"
            };

            var script = AssemblerUtils.BuildScript(scriptString);

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, autoSender.Address, simulator.Nexus.RootChain, DomainSettings.FuelTokenSymbol, 100000);
            simulator.GenerateCustomTransaction(autoSender, ProofOfWork.None,
                                                () => ScriptUtils.BeginScript().AllowGas(autoSender.Address, Address.Null, 1, 9999)
                                                .CallContract("account", "RegisterScript", autoSender.Address, script).SpendGas(autoSender.Address)
                                                .EndScript());
            simulator.EndBlock();


            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, autoSender.Address, simulator.Nexus.RootChain, symbol, 30000);
            simulator.EndBlock();

            var balance = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, symbol, receiver.Address);

            Assert.IsTrue(balance == 30000);
        }
Esempio n. 15
0
        public CLI(string[] args)
        {
            var culture = new CultureInfo("en-US");

            Thread.CurrentThread.CurrentCulture     = culture;
            CultureInfo.DefaultThreadCurrentCulture = culture;

            var seeds = new List <string>();

            var settings = new Arguments(args);

            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");

            restartTime = settings.GetInt("node.reboot", 0);

            showWebLogs = settings.GetBool("web.log", false);
            bool apiLog = settings.GetBool("api.log", true);

            bool hasSync    = settings.GetBool("sync.enabled", true);
            bool hasMempool = settings.GetBool("mempool.enabled", true);
            bool hasEvents  = settings.GetBool("events.enabled", true);
            bool hasRelay   = settings.GetBool("relay.enabled", true);
            bool hasArchive = settings.GetBool("archive.enabled", true);
            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, nexusName, host, threadCount, addressesPerSender);
                Console.WriteLine("Sender finished operations.");
                return;

            case "validator": break;

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

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

            logger.Message("Storage backend: " + storageBackend);

            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 = PhantasmaKeys.FromWIF(wif);

            WalletModule.Keys = PhantasmaKeys.FromWIF(wif);

            if (storageBackend == "file")
            {
                nexus = new Nexus(logger,
                                  (name) => new BasicDiskStore(storagePath + name + ".csv"),
                                  (n) => new SpookOracle(this, n)
                                  );
            }
            else if (storageBackend == "db")
            {
                nexus = new Nexus(logger,
                                  (name) => new DBPartition(storagePath + name),
                                  (n) => new SpookOracle(this, n)
                                  );
            }
            else
            {
                throw new Exception("Backend has to be set to either \"db\" or \"file\"");
            }

            bool bootstrap = false;

            if (!nexus.HasGenesis)
            {
                if (settings.GetBool("nexus.bootstrap"))
                {
                    if (!ValidationUtils.IsValidIdentifier(nexusName))
                    {
                        logger.Error("Invalid nexus name: " + nexusName);
                        this.Terminate();
                        return;
                    }

                    logger.Debug($"Boostraping {nexusName} nexus...");

                    var genesisTimestamp = new Timestamp(settings.GetUInt("genesis.timestamp", Timestamp.Now.Value));

                    bootstrap = true;
                    if (!nexus.CreateGenesisBlock(nexusName, node_keys, genesisTimestamp))
                    {
                        throw new ChainException("Genesis block failure");
                    }

                    logger.Debug("Genesis block created: " + nexus.GetGenesisHash(nexus.RootStorage));
                }
                else
                {
                    logger.Error("No Nexus found.");
                    this.Terminate();
                }
            }
            else
            {
                logger.Success("Loaded Nexus with genesis " + nexus.GetGenesisHash(nexus.RootStorage));
                //seeds.Add("127.0.0.1:7073");
            }

            running = true;

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

            int minimumFee;

            try
            {
                minimumFee = settings.GetInt("mempool.fee", 100000);
                if (minimumFee < 1)
                {
                    logger.Error("Invalid mempool fee value. Expected a positive value.");
                }
            }
            catch (Exception e)
            {
                logger.Error("Invalid mempool fee value. Expected something in fixed point format.");
                return;
            }

            int minimumPow;

            try
            {
                minimumPow = settings.GetInt("mempool.pow", 0);
                int maxPow = 5;
                if (minimumPow < 0 || minimumPow > maxPow)
                {
                    logger.Error($"Invalid mempool pow value. Expected a value between 0 and {maxPow}.");
                }
            }
            catch (Exception e)
            {
                logger.Error("Invalid mempool fee value. Expected something in fixed point format.");
                return;
            }


            if (hasMempool)
            {
                this.mempool = new Mempool(node_keys, nexus, blockTime, minimumFee, System.Text.Encoding.UTF8.GetBytes(Identifier), 0, logger);

                var mempoolLogging = settings.GetBool("mempool.log", true);
                if (mempoolLogging)
                {
                    mempool.OnTransactionFailed    += Mempool_OnTransactionFailed;
                    mempool.OnTransactionAdded     += (hash) => logger.Message($"Received transaction {hash}");
                    mempool.OnTransactionCommitted += (hash) => logger.Message($"Commited transaction {hash}");
                    mempool.OnTransactionDiscarded += (hash) => logger.Message($"Discarded transaction {hash}");
                }

                mempool.Start(ThreadPriority.AboveNormal);
            }
            else
            {
                this.mempool = null;
            }

            PeerCaps caps = PeerCaps.None;

            if (hasSync)
            {
                caps |= PeerCaps.Sync;
            }
            if (hasMempool)
            {
                caps |= PeerCaps.Mempool;
            }
            if (hasEvents)
            {
                caps |= PeerCaps.Events;
            }
            if (hasRelay)
            {
                caps |= PeerCaps.Relay;
            }
            if (hasArchive)
            {
                caps |= PeerCaps.Archive;
            }
            if (hasRPC)
            {
                caps |= PeerCaps.RPC;
            }
            if (hasREST)
            {
                caps |= PeerCaps.REST;
            }

            var possibleCaps = Enum.GetValues(typeof(PeerCaps)).Cast <PeerCaps>().ToArray();

            foreach (var cap in possibleCaps)
            {
                if (cap != PeerCaps.None && caps.HasFlag(cap))
                {
                    logger.Message("Feature enabled: " + cap);
                }
            }

            try
            {
                this.node = new Node("Spook v" + SpookVersion, nexus, mempool, node_keys, port, caps, seeds, logger);
            }
            catch (Exception e)
            {
                logger.Error(e.Message);
                return;
            }

            var useAPICache = settings.GetBool("api.cache", true);

            logger.Message($"API cache is {(useAPICache ? "enabled" : "disabled")}.");
            nexusApi         = new NexusAPI(nexus, useAPICache, apiLog ? logger : null);
            nexusApi.Mempool = mempool;
            nexusApi.Node    = node;

            // RPC setup
            if (hasRPC)
            {
                rpcPort = settings.GetInt("rpc.port", 7077);
                logger.Message($"RPC server listening on port {rpcPort}...");
                var rpcServer = new RPCServer(nexusApi, "/rpc", rpcPort, (level, text) => WebLogMapper("rpc", level, text));
                rpcServer.Start(ThreadPriority.AboveNormal);
            }
            else
            {
                rpcPort = 0;
            }

            // REST setup
            if (hasREST)
            {
                restPort = settings.GetInt("rest.port", 7078);
                logger.Message($"REST server listening on port {restPort}...");
                var restServer = new RESTServer(nexusApi, "/api", restPort, (level, text) => WebLogMapper("rest", level, text));
                restServer.Start(ThreadPriority.AboveNormal);
            }
            else
            {
                restPort = 0;
            }

            var neoScanURL = settings.GetString("neoscan.url", "https://api.neoscan.io");

            var rpcList    = settings.GetString("neo.rpc", "http://seed6.ngd.network:10332,http://seed.neoeconomy.io:10332");
            var neoRpcURLs = rpcList.Split(',');

            this.neoAPI = new Neo.Core.RemoteRPCNode(neoScanURL, neoRpcURLs);
            this.neoAPI.SetLogger((s) => logger.Message(s));

            this.neoScanAPI = new NeoScanAPI(neoScanURL, logger, nexus, node_keys);

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

            node.Start();

            if (gui != null)
            {
                int pluginPeriod = settings.GetInt("plugin.refresh", 1); // in seconds

                if (settings.GetBool("plugin.tps", false))
                {
                    RegisterPlugin(new TPSPlugin(logger, pluginPeriod));
                }

                if (settings.GetBool("plugin.ram", false))
                {
                    RegisterPlugin(new RAMPlugin(logger, pluginPeriod));
                }

                if (settings.GetBool("plugin.mempool", false))
                {
                    RegisterPlugin(new MempoolPlugin(mempool, logger, pluginPeriod));
                }
            }

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

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

            var dispatcher = new CommandDispatcher();

            SetupCommands(dispatcher);

            if (settings.GetBool("swaps.enabled"))
            {
                var tokenSwapper = new TokenSwapper(node_keys, nexusApi, neoScanAPI, neoAPI, minimumFee, logger, settings);
                nexusApi.TokenSwapper = tokenSwapper;

                new Thread(() =>
                {
                    logger.Message("Running token swapping service...");
                    while (running)
                    {
                        Thread.Sleep(5000);

                        if (nodeReady)
                        {
                            tokenSwapper.Update();
                        }
                    }
                }).Start();
            }

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

                    /*
                     * 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, DomainSettings.StakingTokenSymbol, UnitConversion.ToBigInteger(50000, DomainSettings.StakingTokenDecimals));
                     * }
                     * simulator.EndBlock();*/

                    bool fillMarket = settings.GetBool("nacho.market", false);

                    NachoServer.InitNachoServer(nexus, simulator, node_keys, fillMarket, minimumFee, logger);

                    bool genBlocks = settings.GetBool("simulator.blocks", false);
                    if (genBlocks)
                    {
                        int blockNumber = 0;
                        while (running)
                        {
                            Thread.Sleep(5000);
                            blockNumber++;
                            logger.Message("Generating sim block #" + blockNumber);
                            try
                            {
                                simulator.CurrentTime = DateTime.UtcNow;
                                simulator.GenerateRandomBlock();
                            }
                            catch (Exception e)
                            {
                                logger.Error("Fatal error: " + e.ToString());
                                Environment.Exit(-1);
                            }
                        }
                    }

                    MakeReady(dispatcher);
                }).Start();
            }
            else
            {
                MakeReady(dispatcher);
            }

            this.Run();
        }
Esempio n. 16
0
        public void TestSendReceive()
        {
            var test = CreateAPI();

            var simulator = test.simulator;
            var owner     = test.owner;
            var sender    = PhantasmaKeys.Generate();
            var receiver  = PhantasmaKeys.Generate();
            var node      = PhantasmaKeys.FromWIF(nodeWIF);
            var nexus     = simulator.Nexus;
            var api       = test.api;

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, sender.Address, nexus.RootChain, DomainSettings.FuelTokenSymbol, 100000000);
            simulator.EndBlock();

            var desiredChannelBalance = RelayFeePerMessage * 10;

            TopUpChannel(simulator, sender, desiredChannelBalance);

            var channelBalance = nexus.RootChain.InvokeContract(simulator.Nexus.RootStorage, "relay", "GetBalance", sender.Address).AsNumber();

            Assert.IsTrue(channelBalance == desiredChannelBalance);

            var messageCount = 5;
            var messages     = new RelayMessage[messageCount];

            var random = new Random();

            for (int i = 0; i < messageCount; i++)
            {
                var script = new byte[100];
                random.NextBytes(script);

                var message = new RelayMessage
                {
                    nexus     = nexus.Name,
                    index     = i,
                    receiver  = receiver.Address, //node.Address,
                    script    = script,
                    sender    = sender.Address,
                    timestamp = Timestamp.Now
                };
                messages[i] = message;

                var    receipt       = RelayReceipt.FromMessage(message, sender);
                string serializedHex = Base16.Encode(receipt.Serialize());

                api.RelaySend(serializedHex);
            }

            var receipts = (ArrayResult)api.RelayReceive(receiver.Address.Text);

            Assert.IsTrue(receipts.values.Length == messageCount);

            for (int i = 0; i < messageCount; i++)
            {
                var obj = receipts.values[i];
                Assert.IsTrue(obj is ReceiptResult);

                var receiptResult = (ReceiptResult)obj;
                Assert.IsTrue(receiptResult.nexus == messages[i].nexus);
                Assert.IsTrue(new BigInteger(receiptResult.index, 10) == messages[i].index);
                //Assert.IsTrue(receiptResult.receiver == messages[i].receiver);
                //Assert.IsTrue(receiptResult.script == messages[i].script);
                //Assert.IsTrue(receiptResult.sender == messages[i].sender);
                Assert.IsTrue(receiptResult.timestamp == messages[i].timestamp);
            }
        }
Esempio n. 17
0
 public string DecryptName(string name, PhantasmaKeys keys)
 {
     throw new System.NotImplementedException();
 }
Esempio n. 18
0
        public void TestTransactions()
        {
            InitMainNode(7078);

            int addressCount = 20;
            LinkedList <PhantasmaKeys> addressList = new LinkedList <PhantasmaKeys>();

            for (int i = 0; i < addressCount; i++)
            {
                var key = PhantasmaKeys.Generate();

                if (addressList.Contains(key) == false)
                {
                    addressList.AddLast(key);
                }
            }

            var currentKey = addressList.First;

            var masterKeys = PhantasmaKeys.FromWIF(nexusWif);
            //Trace.Message($"Connecting to host: {host} with address {masterKeys.Address.Text}");

            var amount = UnitConversion.ToBigInteger(1000000, DomainSettings.StakingTokenDecimals);
            var hash   = SendTransfer(host, masterKeys, currentKey.Value.Address, amount);

            if (hash == Hash.Null)
            {
                return;
            }

            ConfirmTransaction(host, hash);

            int totalTxs = 0;
            int okTxs    = 0;

            BigInteger currentKeyBalance = GetBalance(currentKey.Value.Address);

            amount = UnitConversion.ToBigInteger(1000000, DomainSettings.FuelTokenDecimals);
            SendTransfer(host, masterKeys, currentKey.Value.Address, amount, "KCAL");

            //while (currentKeyBalance > 9999)
            while (totalTxs < 10)
            {
                var destKey = currentKey.Next != null ? currentKey.Next : addressList.First;

                var txHash = SendTransfer(host, currentKey.Value, destKey.Value.Address, currentKeyBalance - 9999);
                if (txHash == Hash.Null)
                {
                    amount = UnitConversion.ToBigInteger(1000000, DomainSettings.FuelTokenDecimals);
                    SendTransfer(host, masterKeys, currentKey.Value.Address, amount);
                }

                do
                {
                    Thread.Sleep(100);
                } while (!mempool.IsEmpty());

                var confirmation = ConfirmTransaction(host, hash);

                okTxs += confirmation ? 1 : 0;

                totalTxs++;
                currentKey        = destKey;
                currentKeyBalance = GetBalance(currentKey.Value.Address);

                Trace.WriteLine(currentKeyBalance);
            }
            Assert.IsTrue(okTxs == totalTxs);

            CloseNode();
        }
Esempio n. 19
0
 public IEnumerator SignAndSendTransactionWithPayload(PhantasmaKeys keys, string nexus, byte[] script, string chain, string payload, Action <string> callback, Action <EPHANTASMA_SDK_ERROR_TYPE, string> errorHandlingCallback = null)
 {
     return(SignAndSendTransactionWithPayload(keys, nexus, script, chain, Encoding.UTF8.GetBytes(payload), callback, errorHandlingCallback));
 }
Esempio n. 20
0
        public void TestMultiSendSingleClaim()
        {
            var test = CreateAPI();

            var simulator = test.simulator;
            var owner     = test.owner;
            var sender    = PhantasmaKeys.Generate();
            var receiver  = PhantasmaKeys.Generate();
            var node      = PhantasmaKeys.FromWIF(nodeWIF);
            var nexus     = simulator.Nexus;
            var api       = test.api;

            var contractAddress = SmartContract.GetAddressForNative(NativeContractKind.Relay);

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, sender.Address, nexus.RootChain, DomainSettings.FuelTokenSymbol, 100000000);
            simulator.EndBlock();

            TopUpChannel(simulator, sender, 1000000);

            var messageCount = 5;
            var messages     = new RelayMessage[messageCount];

            var random = new Random();

            for (int i = 0; i < messageCount; i++)
            {
                var script = new byte[100];
                random.NextBytes(script);

                var message = new RelayMessage
                {
                    nexus     = nexus.Name,
                    index     = i,
                    receiver  = receiver.Address, //node.Address,
                    script    = script,
                    sender    = sender.Address,
                    timestamp = Timestamp.Now
                };
                messages[i] = message;

                var    receipt       = RelayReceipt.FromMessage(message, sender);
                string serializedHex = Base16.Encode(receipt.Serialize());

                api.RelaySend(serializedHex);
            }

            var receipts = (ArrayResult)api.RelayReceive(receiver.Address.Text);

            Assert.IsTrue(receipts.values.Length == messageCount);

            for (int i = 0; i < messageCount; i++)
            {
                var obj = receipts.values[i];
                Assert.IsTrue(obj is ReceiptResult);

                var receiptResult = (ReceiptResult)obj;
                Assert.IsTrue(receiptResult.nexus == messages[i].nexus);
                Assert.IsTrue(new BigInteger(receiptResult.index, 10) == messages[i].index);
                //Assert.IsTrue(receiptResult.receiver == messages[i].receiver);
                //Assert.IsTrue(receiptResult.script == messages[i].script);
                //Assert.IsTrue(receiptResult.sender == messages[i].sender);
                Assert.IsTrue(receiptResult.timestamp == messages[i].timestamp);
            }

            var lastMessage = messages[messageCount - 1];
            var lastReceipt = RelayReceipt.FromMessage(lastMessage, sender);

            var fuelToken = simulator.Nexus.GetTokenInfo(simulator.Nexus.RootStorage, DomainSettings.FuelTokenSymbol);

            var senderInitialBalance   = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, fuelToken, sender.Address);
            var chainInitialBalance    = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, fuelToken, contractAddress);
            var receiverInitialBalance = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, fuelToken, node.Address);

            simulator.BeginBlock();
            var tx = simulator.GenerateCustomTransaction(sender, ProofOfWork.None, () =>
                                                         ScriptUtils.BeginScript().AllowGas(sender.Address, Address.Null, 1, 9999)
                                                         .CallContract("relay", nameof(RelayContract.SettleChannel), lastReceipt).
                                                         SpendGas(sender.Address).EndScript());

            simulator.EndBlock();

            var txCost = simulator.Nexus.RootChain.GetTransactionFee(tx);

            var senderFinalBalance   = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, fuelToken, sender.Address);
            var chainFinalBalance    = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, fuelToken, contractAddress);
            var receiverFinalBalance = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, fuelToken, receiver.Address);

            var expectedFee = RelayFeePerMessage * messageCount;

            Assert.IsTrue(senderFinalBalance == senderInitialBalance - txCost);
            Assert.IsTrue(receiverFinalBalance == receiverInitialBalance + (expectedFee / 2));
            Assert.IsTrue(chainFinalBalance == chainInitialBalance - (expectedFee / 2));    //the sender's balance is escrowed in the chain address, so the chain just sends the other half of the fee away to the receiver
        }
Esempio n. 21
0
        public void RingSignatures()
        {
            var rand = new Random();

            int participants = 5;
            var messages = new[] { "hello", "phantasma chain", "welcome to the future" }.Select(Encoding.UTF8.GetBytes).ToArray();
            var keys = Enumerable.Range(0, participants).Select(i => RingSignature.GenerateKeyPair(PhantasmaKeys.Generate())).ToArray();

            foreach (var key in keys)
            {
                Assert.IsTrue(BigInteger.ModPow(RingSignature.GroupParameters.Generator, key.PrivateKey, RingSignature.GroupParameters.Prime) == key.PublicKey);
            }

            var publicKeys = keys.Select(k => k.PublicKey).ToArray();

            var signatures = new RingSignature[participants, messages.Length];

            for (int i = 0; i < participants; ++i)
            {
                for (int j = 0; j < messages.Length; ++j)
                {
                    signatures[i, j] = RingSignature.GenerateSignature(messages[j], publicKeys, keys[i].PrivateKey, i);
                    Assert.IsTrue(signatures[i, j].VerifySignature(messages[j], publicKeys));

                    for (int k = 0; k < messages.Length; ++k)
                    {
                        Assert.IsFalse(signatures[i, j].VerifySignature(messages[k], publicKeys) != (k == j));
                    }

                    var orig     = signatures[i, j];
                    var tampered = new RingSignature(orig.Y0, orig.S.FlipBit(rand.Next(orig.S.GetBitLength())), orig.C);
                    Assert.IsFalse(tampered.VerifySignature(messages[j], publicKeys));

                    tampered = new RingSignature(orig.Y0.FlipBit(rand.Next(orig.Y0.GetBitLength())), orig.S, orig.C);
                    Assert.IsFalse(tampered.VerifySignature(messages[j], publicKeys));

                    var s = (BigInteger[])orig.C.Clone();
                    var t = rand.Next(s.Length);
                    s[t]     = s[t].FlipBit(rand.Next(s[t].GetBitLength()));
                    tampered = new RingSignature(orig.Y0, orig.S, s);
                    Assert.IsFalse(tampered.VerifySignature(messages[j], publicKeys));
                }
            }

            for (int i = 0; i < participants; ++i)
            {
                for (int j = 0; j < messages.Length; ++j)
                {
                    for (int k = 0; k < participants; ++k)
                    {
                        for (int l = 0; l < messages.Length; ++l)
                        {
                            Assert.IsTrue(signatures[i, j].IsLinked(signatures[k, l]) == (i == k));
                        }
                    }
                }
            }
        }