//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(); */ }
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(); } }
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); }
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); }
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(); }
public EthereumWallet(PhantasmaKeys keys) : base(keys) { }
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"); }
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)); }
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); }
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)); }
// 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); }
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!"); }
protected override string DeriveAddress(PhantasmaKeys keys) { return(keys.Address.Text); }
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); }
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(); }
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); } }
public string DecryptName(string name, PhantasmaKeys keys) { throw new System.NotImplementedException(); }
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(); }
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)); }
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 }
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)); } } } } }