private void GetBalance(UInt160 assetHash, WalletAccount account) { try { using (ScriptBuilder sb = new ScriptBuilder()) { if (assetHash == Genesis.BcpContractAddress || assetHash == Genesis.BctContractAddress) { sb.EmitSysCall("Zoro.NativeNEP5.Call", "BalanceOf", assetHash, Account.ScriptHash); sb.EmitSysCall("Zoro.NativeNEP5.Call", "Decimals", assetHash); sb.EmitSysCall("Zoro.NativeNEP5.Call", "Symbol", assetHash); } else { sb.EmitAppCall(assetHash, "balanceOf", account.ScriptHash); sb.EmitAppCall(assetHash, "decimals"); sb.EmitAppCall(assetHash, "symbol"); } var script = sb.ToArray().ToHexString(); Zoro.IO.Json.JArray _params = new Zoro.IO.Json.JArray(); _params.Add(""); _params.Add(script); Zoro.IO.Json.JObject info; info = Program.Handler.Process("invokescript", _params); JObject json = JObject.Parse(info.ToString()); string decimals; string symbol = ""; decimal balance = 0.00m; if (json.ContainsKey("stack")) { JArray stack = json["stack"] as JArray; symbol = Encoding.UTF8.GetString(ZoroHelper.HexString2Bytes(stack[2]["value"].ToString())); decimals = BigInteger.Parse(stack[1]["value"].ToString()).ToString(); if (stack[0]["value"].ToString() == "" || stack[1]["value"].ToString() == "" || stack[2]["value"].ToString() == "") { this.lblBalance.Text = "0.00"; this.btnTransfer.Enabled = false; } else { string value = ZoroHelper.GetJsonValue((JObject)stack[0]); balance = Math.Round(decimal.Parse(value) / (decimal)Math.Pow(10, double.Parse(decimals)), int.Parse(decimals)); if (balance != 0) { this.btnTransfer.Enabled = true; } } Account = account; AssetHash = assetHash; AssetSymbol = symbol; Decimals = int.Parse(decimals); } this.lblAsset.Text = assetHash.ToString() + "(" + symbol + ")"; this.lblBalance.Text = balance.ToString(); } } catch { return; } }
public void FeeIsSignatureContract_TestScope_Global_Default() { // Global is supposed to be default Cosigner cosigner = new Cosigner(); cosigner.Scopes.Should().Be(WitnessScope.Global); var wallet = TestUtils.GenerateTestWallet(); var snapshot = Blockchain.Singleton.GetSnapshot(); // no password on this wallet using (var unlock = wallet.Unlock("")) { var acc = wallet.CreateAccount(); // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new Nep5AccountState())); entry.GetInteroperable <Nep5AccountState>().Balance = 10000 * NativeContract.GAS.Factor; snapshot.Commit(); // Make transaction // Manually creating script byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { // self-transfer of 1e-8 GAS System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value; sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); } // default to global scope var cosigners = new Cosigner[] { new Cosigner { Account = acc.ScriptHash } }; // using this... var tx = wallet.MakeTransaction(script, acc.ScriptHash, cosigners); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); // ---- // Sign // ---- var data = new ContractParametersContext(tx); bool signed = wallet.Sign(data); Assert.IsTrue(signed); // get witnesses from signed 'data' tx.Witnesses = data.GetWitnesses(); tx.Witnesses.Length.Should().Be(1); // Fast check Assert.IsTrue(tx.VerifyWitnesses(snapshot, tx.NetworkFee)); // Check long verificationGas = 0; foreach (var witness in tx.Witnesses) { using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) { engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); Assert.IsTrue(engine.ResultStack.Pop().ToBoolean()); verificationGas += engine.GasConsumed; } } // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); // final check on sum: verification_cost + tx_size Assert.AreEqual(1264390, verificationGas + sizeGas); // final assert Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas); } }
public Transaction MakeTransaction(List <TransactionAttribute> attributes, IEnumerable <TransferOutput> outputs, UInt160 from = null, UInt160 fee_address = null, UInt160 change_address = null, Fixed8 fee = default(Fixed8)) { var cOutputs = outputs.Where(p => !p.IsGlobalAsset).GroupBy(p => new { AssetId = (UInt160)p.AssetId, Account = p.ScriptHash }, (k, g) => new { k.AssetId, Value = g.Aggregate(BigInteger.Zero, (x, y) => x + y.Value.Value), k.Account }).ToArray(); Transaction tx; if (attributes == null) { attributes = new List <TransactionAttribute>(); } if (cOutputs.Length == 0) { tx = new ContractTransaction(); } else { UInt160[] accounts = from == null?GetAccounts().Where(p => !p.Lock && !p.WatchOnly).Select(p => p.ScriptHash).ToArray() : new[] { from }; HashSet <UInt160> sAttributes = new HashSet <UInt160>(); using (ScriptBuilder sb = new ScriptBuilder()) { foreach (var output in cOutputs) { var balances = new List <(UInt160 Account, BigInteger Value)>(); foreach (UInt160 account in accounts) { byte[] script; using (ScriptBuilder sb2 = new ScriptBuilder()) { sb2.EmitAppCall(output.AssetId, "balanceOf", account); script = sb2.ToArray(); } ApplicationEngine engine = ApplicationEngine.Run(script); if (engine.State.HasFlag(VMState.FAULT)) { return(null); } balances.Add((account, engine.ResultStack.Pop().GetBigInteger())); } BigInteger sum = balances.Aggregate(BigInteger.Zero, (x, y) => x + y.Value); if (sum < output.Value) { return(null); } if (sum != output.Value) { balances = balances.OrderByDescending(p => p.Value).ToList(); BigInteger amount = output.Value; int i = 0; while (balances[i].Value <= amount) { amount -= balances[i++].Value; } if (amount == BigInteger.Zero) { balances = balances.Take(i).ToList(); } else { balances = balances.Take(i).Concat(new[] { balances.Last(p => p.Value >= amount) }).ToList(); } sum = balances.Aggregate(BigInteger.Zero, (x, y) => x + y.Value); } sAttributes.UnionWith(balances.Select(p => p.Account)); for (int i = 0; i < balances.Count; i++) { BigInteger value = balances[i].Value; if (i == 0) { BigInteger change = sum - output.Value; if (change > 0) { value -= change; } } sb.EmitAppCall(output.AssetId, "transfer", balances[i].Account, output.Account, value); sb.Emit(OpCode.THROWIFNOT); } } byte[] nonce = new byte[8]; rand.NextBytes(nonce); sb.Emit(OpCode.RET, nonce); tx = new InvocationTransaction { Version = 1, Script = sb.ToArray() }; } attributes.AddRange(sAttributes.Select(p => new TransactionAttribute { Usage = TransactionAttributeUsage.Script, Data = p.ToArray() })); } tx.Attributes = attributes.ToArray(); tx.Inputs = new CoinReference[0]; tx.Outputs = outputs.Where(p => p.IsGlobalAsset).Select(p => p.ToTxOutput()).ToArray(); tx.Witnesses = new Witness[0]; if (tx is InvocationTransaction itx) { ApplicationEngine engine = ApplicationEngine.Run(itx.Script, itx); if (engine.State.HasFlag(VMState.FAULT)) { return(null); } tx = new InvocationTransaction { Version = itx.Version, Script = itx.Script, Gas = InvocationTransaction.GetGas(engine.GasConsumed), Attributes = itx.Attributes, Inputs = itx.Inputs, Outputs = itx.Outputs }; } tx = transactionContract.MakeTransaction(this, tx, from, fee_address, change_address, fee);//By BHP return(tx); }
async Task test_mintTokens() { decimal amount = 0; while (true) { subPrintLine("Input amount:"); string str_amount = Console.ReadLine(); try { amount = decimal.Parse(str_amount); break; } catch (Exception e) { subPrintLine("input number"); } } //获取地址的资产列表 Dictionary <string, List <Utxo> > dir = await Helper.GetBalanceByAddress(Config.api, address); if (dir.ContainsKey(Config.id_GAS) == false) { subPrintLine("no gas"); return; } Transaction tran = null; { byte[] script = null; using (var sb = new ScriptBuilder()) { var array = new MyJson.JsonNode_Array(); sb.EmitParamJson(array); //参数倒序入 sb.EmitParamJson(new MyJson.JsonNode_ValueString("(str)mintTokens")); //参数倒序入 Hash160 shash = Config.dapp_sgas; sb.EmitAppCall(shash); //nep5脚本 script = sb.ToArray(); } var sgasScripthash = Config.dapp_sgas; var targetaddr = ThinNeo.Helper.GetAddressFromScriptHash(sgasScripthash); subPrintLine("contract address=" + targetaddr);//往合约地址转账 //生成交易 tran = Helper.makeTran(dir[Config.id_GAS], targetaddr, new Hash256(Config.id_GAS), amount, (decimal)0.00000001); tran.type = TransactionType.InvocationTransaction; var idata = new InvokeTransData(); tran.extdata = idata; idata.script = script; idata.gas = (decimal)0.00000001; //sign and broadcast var signdata = ThinNeo.Helper.Sign(tran.GetMessage(), prikey); tran.AddWitness(signdata, pubkey, address); var trandata = tran.GetRawData(); var strtrandata = ThinNeo.Helper.Bytes2HexString(trandata); byte[] postdata; var a = "d1012200c10a6d696e74546f6b656e7367be0da5478954f03c44c06d63bf613dc98c621e96010000000000000000011a47bddefb7d8fff356c939a1fed120d2848464f4ed719cf9134767a822dc936010002e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c6000e1f50500000000be0da5478954f03c44c06d63bf613dc98c621e96e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c603e5dd190000000005ffb879d70015f9f8407eaad6adc3e196d8fbeac014140e6f9f97d589a6353f21ba25da7c1f430af10206d7a10597af22dc7d9c8aecef52338da3d1880a7edcc2178823fc7251ff3cb693e39da8da1c352eb3cc4f27045232103aa9038ee904c71cecf450c88a7ff0d23891d6cdc24b1eeb50bfd0e305fbec26bac"; var aa = ThinNeo.Helper.HexString2Bytes(a); var tran2 = new Transaction(); tran2.Deserialize(new System.IO.MemoryStream(aa)); var url = Helper.MakeRpcUrlPost(Config.api, "sendrawtransaction", out postdata, new MyJson.JsonNode_ValueString(strtrandata)); var result = await Helper.HttpPost(url, postdata); subPrintLine("得到的结果是:" + result); var json = MyJson.Parse(result).AsDict(); if (json.ContainsKey("result")) { var resultv = json["result"].AsList()[0].AsDict(); var txid = resultv["txid"].AsString(); subPrintLine("txid=" + txid); } } }
public static async Task <string> api_SendbatchTransaction(byte[] prikey, Hash160 schash, string methodname, params string[] subparam) { byte[] pubkey = ThinNeo.Helper.GetPublicKeyFromPrivateKey(prikey); string address = ThinNeo.Helper.GetAddressFromPublicKey(pubkey); byte[] data = null; using (ScriptBuilder sb = new ScriptBuilder()) { MyJson.JsonNode_Array array = new MyJson.JsonNode_Array(); byte[] randombytes = new byte[32]; using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) { rng.GetBytes(randombytes); } BigInteger randomNum = new BigInteger(randombytes); sb.EmitPushNumber(randomNum); sb.Emit(ThinNeo.VM.OpCode.DROP); if (subparam != null && subparam.Length > 0) { for (var i = 0; i < subparam.Length; i++) { array.AddArrayValue(subparam[i]); } } sb.EmitParamJson(array); sb.EmitPushString(methodname); sb.EmitAppCall(schash); data = sb.ToArray(); } //MakeTran ThinNeo.Transaction tran = new ThinNeo.Transaction(); tran.version = 0;//0 or 1 tran.inputs = new ThinNeo.TransactionInput[0]; tran.outputs = new ThinNeo.TransactionOutput[0]; tran.type = ThinNeo.TransactionType.InvocationTransaction; tran.extdata = new ThinNeo.InvokeTransData(); var idata = new ThinNeo.InvokeTransData(); tran.extdata = idata; idata.script = data; idata.gas = 0; tran.attributes = new ThinNeo.Attribute[1]; tran.attributes[0] = new ThinNeo.Attribute(); tran.attributes[0].usage = ThinNeo.TransactionAttributeUsage.Script; tran.attributes[0].data = ThinNeo.Helper.GetPublicKeyHashFromAddress(address); //sign and broadcast var signdata = ThinNeo.Helper.Sign(tran.GetMessage(), prikey); tran.AddWitness(signdata, pubkey, address); var trandata = tran.GetRawData(); var strtrandata = ThinNeo.Helper.Bytes2HexString(trandata); byte[] postdata; var url = Helper.MakeRpcUrlPost(Config.api, "sendrawtransaction", out postdata, new MyJson.JsonNode_ValueString(strtrandata)); var result = await Helper.HttpPost(url, postdata); return(result); }
private void timer1_Tick(object sender, EventArgs e) { uint walletHeight = 0; if (Program.CurrentWallet != null) { walletHeight = (Program.CurrentWallet.WalletHeight > 0) ? Program.CurrentWallet.WalletHeight - 1 : 0; } lbl_height.Text = $"{walletHeight}/{Blockchain.Singleton.Height}/{Blockchain.Singleton.HeaderHeight}"; lbl_count_node.Text = LocalNode.Singleton.ConnectedCount.ToString(); TimeSpan persistence_span = DateTime.UtcNow - persistence_time; if (persistence_span < TimeSpan.Zero) { persistence_span = TimeSpan.Zero; } if (persistence_span > Blockchain.TimePerBlock) { toolStripProgressBar1.Style = ProgressBarStyle.Marquee; } else { toolStripProgressBar1.Value = persistence_span.Seconds; toolStripProgressBar1.Style = ProgressBarStyle.Blocks; } if (Program.CurrentWallet != null) { if (Program.CurrentWallet.WalletHeight <= Blockchain.Singleton.Height + 1) { if (balance_changed) { using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) { IEnumerable <Coin> coins = Program.CurrentWallet?.GetCoins().Where(p => !p.State.HasFlag(CoinState.Spent)) ?? Enumerable.Empty <Coin>(); Fixed8 bonus_available = snapshot.CalculateBonus(Program.CurrentWallet.GetUnclaimedCoins().Select(p => p.Reference)); Fixed8 bonus_unavailable = snapshot.CalculateBonus(coins.Where(p => p.State.HasFlag(CoinState.Confirmed) && p.Output.AssetId.Equals(Blockchain.GoverningToken.Hash)).Select(p => p.Reference), snapshot.Height + 1); Fixed8 bonus = bonus_available + bonus_unavailable; var assets = coins.GroupBy(p => p.Output.AssetId, (k, g) => new { Asset = snapshot.Assets.TryGet(k), Value = g.Sum(p => p.Output.Value), Claim = k.Equals(Blockchain.UtilityToken.Hash) ? bonus : Fixed8.Zero }).ToDictionary(p => p.Asset.AssetId); if (bonus != Fixed8.Zero && !assets.ContainsKey(Blockchain.UtilityToken.Hash)) { assets[Blockchain.UtilityToken.Hash] = new { Asset = snapshot.Assets.TryGet(Blockchain.UtilityToken.Hash), Value = Fixed8.Zero, Claim = bonus }; } var balance_ans = coins.Where(p => p.Output.AssetId.Equals(Blockchain.GoverningToken.Hash)).GroupBy(p => p.Output.ScriptHash).ToDictionary(p => p.Key, p => p.Sum(i => i.Output.Value)); var balance_anc = coins.Where(p => p.Output.AssetId.Equals(Blockchain.UtilityToken.Hash)).GroupBy(p => p.Output.ScriptHash).ToDictionary(p => p.Key, p => p.Sum(i => i.Output.Value)); foreach (ListViewItem item in listView1.Items) { UInt160 script_hash = item.Name.ToScriptHash(); Fixed8 ans = balance_ans.ContainsKey(script_hash) ? balance_ans[script_hash] : Fixed8.Zero; Fixed8 anc = balance_anc.ContainsKey(script_hash) ? balance_anc[script_hash] : Fixed8.Zero; item.SubItems["ans"].Text = ans.ToString(); item.SubItems["anc"].Text = anc.ToString(); } foreach (AssetState asset in listView2.Items.OfType <ListViewItem>().Select(p => p.Tag as AssetState).Where(p => p != null).ToArray()) { if (!assets.ContainsKey(asset.AssetId)) { listView2.Items.RemoveByKey(asset.AssetId.ToString()); } } foreach (var asset in assets.Values) { string value_text = asset.Value.ToString() + (asset.Asset.AssetId.Equals(Blockchain.UtilityToken.Hash) ? $"+({asset.Claim})" : ""); if (listView2.Items.ContainsKey(asset.Asset.AssetId.ToString())) { listView2.Items[asset.Asset.AssetId.ToString()].SubItems["value"].Text = value_text; } else { string asset_name = asset.Asset.AssetType == AssetType.GoverningToken ? "OXS" : asset.Asset.AssetType == AssetType.UtilityToken ? "OXC" : asset.Asset.GetName(); listView2.Items.Add(new ListViewItem(new[] { new ListViewItem.ListViewSubItem { Name = "name", Text = asset_name }, new ListViewItem.ListViewSubItem { Name = "type", Text = asset.Asset.AssetType.ToString() }, new ListViewItem.ListViewSubItem { Name = "value", Text = value_text }, new ListViewItem.ListViewSubItem { ForeColor = Color.Gray, Name = "issuer", Text = $"{LanHelper.LocalLanguage("unknown issuer")}[{asset.Asset.Owner}]" } }, -1, listView2.Groups["unchecked"]) { Name = asset.Asset.AssetId.ToString(), Tag = asset.Asset, UseItemStyleForSubItems = false }); } } balance_changed = false; } } foreach (ListViewItem item in listView2.Groups["unchecked"].Items.OfType <ListViewItem>().ToArray()) { ListViewItem.ListViewSubItem subitem = item.SubItems["issuer"]; AssetState asset = (AssetState)item.Tag; CertificateQueryResult result; if (asset.AssetType == AssetType.GoverningToken || asset.AssetType == AssetType.UtilityToken) { result = new CertificateQueryResult { Type = CertificateQueryResultType.System }; } else { result = CertificateQueryService.Query(asset.Owner); } using (result) { subitem.Tag = result.Type; switch (result.Type) { case CertificateQueryResultType.Querying: case CertificateQueryResultType.QueryFailed: break; case CertificateQueryResultType.System: subitem.ForeColor = Color.Green; subitem.Text = LanHelper.LocalLanguage("OX system"); break; case CertificateQueryResultType.Invalid: subitem.ForeColor = Color.Red; subitem.Text = $"[{ LanHelper.LocalLanguage("Invalid")}][{asset.Owner}]"; break; case CertificateQueryResultType.Expired: subitem.ForeColor = Color.Yellow; subitem.Text = $"[{LanHelper.LocalLanguage("Expired")}]{result.Certificate.Subject}[{asset.Owner}]"; break; case CertificateQueryResultType.Good: subitem.ForeColor = Color.Black; subitem.Text = $"{result.Certificate.Subject}[{asset.Owner}]"; break; } switch (result.Type) { case CertificateQueryResultType.System: case CertificateQueryResultType.Missing: case CertificateQueryResultType.Invalid: case CertificateQueryResultType.Expired: case CertificateQueryResultType.Good: item.Group = listView2.Groups["checked"]; break; } } } } if (check_nep5_balance && persistence_span > TimeSpan.FromSeconds(2)) { UInt160[] addresses = Program.CurrentWallet.GetAccounts().Select(p => p.ScriptHash).ToArray(); foreach (string s in Settings.Default.NEP5Watched) { UInt160 script_hash = UInt160.Parse(s); byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { foreach (UInt160 address in addresses) { sb.EmitAppCall(script_hash, "balanceOf", address); } sb.Emit(OpCode.DEPTH, OpCode.PACK); sb.EmitAppCall(script_hash, "decimals"); sb.EmitAppCall(script_hash, "name"); script = sb.ToArray(); } ApplicationEngine engine = ApplicationEngine.Run(script); if (engine.State.HasFlag(VMState.FAULT)) { continue; } string name = engine.ResultStack.Pop().GetString(); byte decimals = (byte)engine.ResultStack.Pop().GetBigInteger(); BigInteger amount = ((VMArray)engine.ResultStack.Pop()).Aggregate(BigInteger.Zero, (x, y) => x + y.GetBigInteger()); if (amount == 0) { listView2.Items.RemoveByKey(script_hash.ToString()); continue; } BigDecimal balance = new BigDecimal(amount, decimals); string value_text = balance.ToString(); if (listView2.Items.ContainsKey(script_hash.ToString())) { listView2.Items[script_hash.ToString()].SubItems["value"].Text = value_text; } else { listView2.Items.Add(new ListViewItem(new[] { new ListViewItem.ListViewSubItem { Name = "name", Text = name }, new ListViewItem.ListViewSubItem { Name = "type", Text = "NEP-5" }, new ListViewItem.ListViewSubItem { Name = "value", Text = value_text }, new ListViewItem.ListViewSubItem { ForeColor = Color.Gray, Name = "issuer", Text = $"ScriptHash:{script_hash}" } }, -1, listView2.Groups["checked"]) { Name = script_hash.ToString(), UseItemStyleForSubItems = false }); } } check_nep5_balance = false; } } }
public void Runtime_GetNotifications_Test() { UInt160 scriptHash2; var snapshot = Blockchain.Singleton.GetSnapshot(); using (var script = new ScriptBuilder()) { // Drop arguments script.Emit(OpCode.NIP); // Notify method script.EmitSysCall(InteropService.Runtime.Notify); // Add return script.EmitPush(true); // Mock contract scriptHash2 = script.ToArray().ToScriptHash(); snapshot.Contracts.Delete(scriptHash2); snapshot.Contracts.Add(scriptHash2, new Neo.Ledger.ContractState() { Script = script.ToArray(), Manifest = ContractManifest.CreateDefault(scriptHash2), }); } // Wrong length using (var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true)) using (var script = new ScriptBuilder()) { // Retrive script.EmitPush(1); script.EmitSysCall(InteropService.Runtime.GetNotifications); // Execute engine.LoadScript(script.ToArray()); Assert.AreEqual(VMState.FAULT, engine.Execute()); } // All test using (var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true)) using (var script = new ScriptBuilder()) { // Notification 1 -> 13 script.EmitPush(13); script.EmitSysCall(InteropService.Runtime.Notify); // Call script script.EmitAppCall(scriptHash2, "test"); // Drop return script.Emit(OpCode.DROP); // Receive all notifications script.Emit(OpCode.PUSHNULL); script.EmitSysCall(InteropService.Runtime.GetNotifications); // Execute engine.LoadScript(script.ToArray()); var currentScriptHash = engine.EntryScriptHash; Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); Assert.AreEqual(2, engine.Notifications.Count); Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(VM.Types.Array)); var array = (VM.Types.Array)engine.ResultStack.Pop(); // Check syscall result AssertNotification(array[1], scriptHash2, "test"); AssertNotification(array[0], currentScriptHash, 13); // Check notifications Assert.AreEqual(scriptHash2, engine.Notifications[1].ScriptHash); Assert.AreEqual("test", engine.Notifications[1].State.GetString()); Assert.AreEqual(currentScriptHash, engine.Notifications[0].ScriptHash); Assert.AreEqual(13, engine.Notifications[0].State.GetBigInteger()); } // Script notifications using (var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true)) using (var script = new ScriptBuilder()) { // Notification 1 -> 13 script.EmitPush(13); script.EmitSysCall(InteropService.Runtime.Notify); // Call script script.EmitAppCall(scriptHash2, "test"); // Drop return script.Emit(OpCode.DROP); // Receive all notifications script.EmitPush(scriptHash2.ToArray()); script.EmitSysCall(InteropService.Runtime.GetNotifications); // Execute engine.LoadScript(script.ToArray()); var currentScriptHash = engine.EntryScriptHash; Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); Assert.AreEqual(2, engine.Notifications.Count); Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(VM.Types.Array)); var array = (VM.Types.Array)engine.ResultStack.Pop(); // Check syscall result AssertNotification(array[0], scriptHash2, "test"); // Check notifications Assert.AreEqual(scriptHash2, engine.Notifications[1].ScriptHash); Assert.AreEqual("test", engine.Notifications[1].State.GetString()); Assert.AreEqual(currentScriptHash, engine.Notifications[0].ScriptHash); Assert.AreEqual(13, engine.Notifications[0].State.GetBigInteger()); } // Clean storage snapshot.Contracts.Delete(scriptHash2); }
/// <summary> /// apply for new validator /// </summary> /// <param name="pubkey"></param> /// <returns></returns> public async Task <object> ApplyForValidator(string pubkey) { if (CurrentWallet == null) { return(Error(ErrorCode.WalletNotOpen)); } if (pubkey.IsNull()) { return(Error(ErrorCode.ParameterIsNull)); } ECPoint publicKey = null; try { publicKey = ECPoint.Parse(pubkey, ECCurve.Secp256r1); } catch (Exception e) { return(Error(ErrorCode.InvalidPara)); } using var snapshot = Blockchain.Singleton.GetSnapshot(); var validators = NativeContract.NEO.GetRegisteredValidators(snapshot); if (validators.Any(v => v.PublicKey.ToString() == pubkey)) { return(Error(ErrorCode.ValidatorAlreadyExist)); } VerificationContract contract = new VerificationContract { Script = SmartContract.Contract.CreateSignatureRedeemScript(publicKey), ParameterList = new[] { ContractParameterType.Signature } }; var account = contract.ScriptHash; using ScriptBuilder sb = new ScriptBuilder(); sb.EmitAppCall(NativeContract.NEO.Hash, "registerValidator", publicKey); Transaction tx = null; try { tx = CurrentWallet.InitTransaction(sb.ToArray(), account); } catch (InvalidOperationException) { return(Error(ErrorCode.EngineFault)); } catch (Exception ex) { if (ex.Message.Contains("Insufficient GAS")) { return(Error(ErrorCode.GasNotEnough)); } throw; } var(signSuccess, context) = CurrentWallet.TrySignTx(tx); if (!signSuccess) { return(Error(ErrorCode.SignFail, context.SafeSerialize())); } var result = new VoteResultModel(); await tx.Broadcast(); result.TxId = tx.Hash; return(result); }
/// <summary> /// vote for consensus node /// </summary> /// <returns></returns> public async Task <object> VoteCN(UInt160 account, string[] pubkeys) { if (CurrentWallet == null) { return(Error(ErrorCode.WalletNotOpen)); } if (account == null || pubkeys.IsEmpty()) { return(Error(ErrorCode.ParameterIsNull)); } ECPoint[] publicKeys = null; try { publicKeys = pubkeys.Select(p => ECPoint.Parse(p, ECCurve.Secp256r1)).ToArray(); } catch (Exception e) { return(Error(ErrorCode.InvalidPara)); } using ScriptBuilder sb = new ScriptBuilder(); sb.EmitAppCall(NativeContract.NEO.Hash, "vote", new ContractParameter { Type = ContractParameterType.Hash160, Value = account }, new ContractParameter { Type = ContractParameterType.Array, Value = publicKeys.Select(p => new ContractParameter { Type = ContractParameterType.PublicKey, Value = p }).ToArray() }); Transaction tx = null; try { tx = CurrentWallet.InitTransaction(sb.ToArray(), account); } catch (InvalidOperationException) { return(Error(ErrorCode.EngineFault)); } catch (Exception ex) { if (ex.Message.Contains("Insufficient GAS")) { return(Error(ErrorCode.GasNotEnough)); } throw; } var(signSuccess, context) = CurrentWallet.TrySignTx(tx); if (!signSuccess) { return(Error(ErrorCode.SignFail, context.SafeSerialize())); } var result = new VoteResultModel(); await tx.Broadcast(); result.TxId = tx.Hash; return(result); }
private Transaction GenerateTransaction() { var cOutputs = this.Items.Where(p => p.AssetId is UInt160).GroupBy(p => new { AssetId = (UInt160)p.AssetId, Account = p.ScriptHash }, (k, g) => new { AssetId = k.AssetId, Value = g.Aggregate(BigInteger.Zero, (x, y) => x + y.Value.Value), Account = k.Account }).ToArray(); Transaction tx; var attributes = new List <TransactionAttribute>(); if (cOutputs.Length == 0) { tx = new ContractTransaction(); } else { var addresses = this.walletController.GetAccounts().Select(p => p.ScriptHash).ToArray(); var sAttributes = new HashSet <UInt160>(); using (var builder = new ScriptBuilder()) { foreach (var output in cOutputs) { byte[] script; using (var builder2 = new ScriptBuilder()) { foreach (var address in addresses) { builder2.EmitAppCall(output.AssetId, "balanceOf", address); } builder2.Emit(OpCode.DEPTH, OpCode.PACK); script = builder2.ToArray(); } var engine = ApplicationEngine.Run(script); if (engine.State.HasFlag(VMState.FAULT)) { return(null); } var balances = engine.EvaluationStack.Pop().GetArray().Reverse().Zip(addresses, (i, a) => new { Account = a, Value = i.GetBigInteger() }).ToArray(); var sum = balances.Aggregate(BigInteger.Zero, (x, y) => x + y.Value); if (sum < output.Value) { return(null); } if (sum != output.Value) { balances = balances.OrderByDescending(p => p.Value).ToArray(); var amount = output.Value; var i = 0; while (balances[i].Value <= amount) { amount -= balances[i++].Value; } balances = amount == BigInteger.Zero ? balances.Take(i).ToArray() : balances.Take(i).Concat(new[] { balances.Last(p => p.Value >= amount) }).ToArray(); sum = balances.Aggregate(BigInteger.Zero, (x, y) => x + y.Value); } sAttributes.UnionWith(balances.Select(p => p.Account)); for (int i = 0; i < balances.Length; i++) { var value = balances[i].Value; if (i == 0) { var change = sum - output.Value; if (change > 0) { value -= change; } } builder.EmitAppCall(output.AssetId, "transfer", balances[i].Account, output.Account, value); builder.Emit(OpCode.THROWIFNOT); } } tx = new InvocationTransaction { Version = 1, Script = builder.ToArray() }; } attributes.AddRange(sAttributes.Select(p => new TransactionAttribute { Usage = TransactionAttributeUsage.Script, Data = p.ToArray() })); } if (!string.IsNullOrEmpty(remark)) { attributes.Add(new TransactionAttribute { Usage = TransactionAttributeUsage.Remark, Data = Encoding.UTF8.GetBytes(remark) }); } tx.Attributes = attributes.ToArray(); tx.Outputs = this.Items.Where(p => p.AssetId is UInt256).Select(p => p.ToTxOutput()).ToArray(); if (tx is ContractTransaction ctx) { tx = this.walletController.MakeTransaction(ctx); } return(tx); }
public async Task <object> InvokeContract(InvokeContractParameterModel para) { if (CurrentWallet == null) { return(Error(ErrorCode.WalletNotOpen)); } if (para.ContractHash == null || para.Method.IsNull()) { return(Error(ErrorCode.ParameterIsNull)); } using var snapshot = Blockchain.Singleton.GetSnapshot(); var contract = snapshot.Contracts.TryGet(para.ContractHash); if (contract == null) { return(Error(ErrorCode.UnknownContract)); } ContractParameter[] contractParameters = para.Parameters?.Select(p => { var parameterValue = new ContractParameter(p.Type); parameterValue.SetValue(p.Value); return(parameterValue); }).ToArray(); var signers = new List <Cosigner>(); if (para.Cosigners.NotEmpty()) { signers.AddRange(para.Cosigners.Select(s => new Cosigner() { Account = s.Account, Scopes = s.Scopes })); } Transaction tx = null; using ScriptBuilder sb = new ScriptBuilder(); sb.EmitAppCall(para.ContractHash, para.Method, contractParameters); try { tx = CurrentWallet.InitTransaction(sb.ToArray(), signers.ToArray()); } catch (InvalidOperationException) { return(Error(ErrorCode.EngineFault)); } catch (Exception ex) { if (ex.Message.Contains("Insufficient GAS")) { return(Error(ErrorCode.GasNotEnough)); } throw; } var(signSuccess, context) = CurrentWallet.TrySignTx(tx); if (!signSuccess) { return(Error(ErrorCode.SignFail, context.SafeSerialize())); } var result = new InvokeResultModel(); using ApplicationEngine engine = ApplicationEngine.Run(tx.Script, tx, testMode: true); result.VmState = engine.State; result.GasConsumed = new BigDecimal(tx.SystemFee, NativeContract.GAS.Decimals); result.ResultStack = engine.ResultStack.Select(p => JStackItem.FromJson(p.ToParameter().ToJson())).ToList(); if (engine.State.HasFlag(VMState.FAULT)) { return(Error(ErrorCode.EngineFault)); } if (!para.SendTx) { return(result); } await tx.Broadcast(); result.TxId = tx.Hash; return(result); }
public async Task <JObject> sendTransaction(byte[] prikey, Hash160 schash, string method, string[] subparam) { // 构造合约交易 byte[] data = null; using (ScriptBuilder sb = new ScriptBuilder()) { MyJson.JsonNode_Array array = new MyJson.JsonNode_Array(); // byte[] randombytes = new byte[32]; using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) { rng.GetBytes(randombytes); } BigInteger randomNum = new BigInteger(randombytes); sb.EmitPushNumber(randomNum); sb.Emit(ThinNeo.VM.OpCode.DROP); for (var i = 0; i < subparam.Length; i++) { array.AddArrayValue(subparam[i]); } sb.EmitParamJson(array); sb.EmitPushString(method); sb.EmitAppCall(schash); data = sb.ToArray(); } // 获取余额 //string id_nnc = assetid; Dictionary <string, List <Utxo> > dir = getBalance(accountInfo.address); if (dir == null || dir[id_gas] == null) { // 余额不足 return(insufficientBalance()); } // 构造并签名 var tran = new ThinNeo.Transaction(); tran.type = ThinNeo.TransactionType.InvocationTransaction; tran.extdata = new ThinNeo.InvokeTransData { script = data, gas = 0 }; tran.inputs = new ThinNeo.TransactionInput[0]; tran.outputs = new ThinNeo.TransactionOutput[0]; tran.attributes = new ThinNeo.Attribute[1]; tran.attributes[0] = new ThinNeo.Attribute(); tran.attributes[0].usage = TransactionAttributeUsage.Script; tran.attributes[0].data = ThinNeo.Helper.GetPublicKeyHashFromAddress(accountInfo.address); byte[] signdata = ThinNeo.Helper.Sign(tran.GetMessage(), prikey); tran.AddWitness(signdata, accountInfo.pubkey, accountInfo.address); string txid = tran.GetHash().ToString(); byte[] transdata = tran.GetRawData(); string rawdata = ThinNeo.Helper.Bytes2HexString(transdata); // 发送交易 try { byte[] postdata; string url = TransHelper.MakeRpcUrlPost(nelJsonRpcUrl, "sendrawtransaction", out postdata, new MyJson.JsonNode_ValueString(rawdata)); var result = await TransHelper.HttpPost(url, postdata); Console.WriteLine("result:" + result); if (JObject.Parse(result)["result"] == null) { return(txFail(txid)); } JObject res = (JObject)(((JArray)(JObject.Parse(result)["result"]))[0]); string flag = res["sendrawtransactionresult"].ToString(); if (flag.ToLower() != "true" && res["txid"].ToString() != txid) { return(txFail(txid)); } return(txSucc(txid)); } catch (Exception) { return(txFail(txid)); } }
internal static bool VerifyScripts(this IVerifiable verifiable) { bool bLog = false; string logpath = ""; if (verifiable is Transaction) { var hash = (verifiable as Transaction).Hash; if (Neo.SmartContract.Debug.FullLog.TestNeedLog(hash)) { bLog = true; logpath = System.IO.Path.Combine(Neo.SmartContract.Debug.FullLog.Path, hash.ToString()); } } UInt160[] hashes; try { hashes = verifiable.GetScriptHashesForVerifying(); } catch (InvalidOperationException) { return(false); } if (hashes.Length != verifiable.Scripts.Length) { return(false); } for (int i = 0; i < hashes.Length; i++) { byte[] verification = verifiable.Scripts[i].VerificationScript; if (verification.Length == 0) { using (ScriptBuilder sb = new ScriptBuilder()) { sb.EmitAppCall(hashes[i].ToArray()); verification = sb.ToArray(); } } else { if (hashes[i] != verifiable.Scripts[i].ScriptHash) { return(false); } } using (StateReader service = new StateReader()) { ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, Blockchain.Default, service, Fixed8.Zero); if (bLog) { engine.BeginDebug(); } engine.LoadScript(verification, false); engine.LoadScript(verifiable.Scripts[i].InvocationScript, true); if (!engine.Execute()) { return(false); } if (bLog) { string filename = logpath + "[" + i + "].llvmhex.txt"; if (engine.FullLog != null) { engine.FullLog.Save(filename); } } if (engine.EvaluationStack.Count != 1 || !engine.EvaluationStack.Pop().GetBoolean()) { return(false); } } } return(true); }
/// <summary> /// Transfer NEP5 tokens. /// </summary> /// <param name="attributes"></param> /// <param name="outputs"></param> /// <param name="changeAddress"></param> /// <param name="fee"></param> /// <returns></returns> public override async Task <Transaction> TransferNep5(List <TransactionAttribute> attributes, IEnumerable <TransferOutput> outputs, UInt160 changeAddress = null, decimal fee = 0) { InvocationTransaction tx; var cOutputs = outputs.Where(p => !p.IsGlobalAsset).GroupBy(p => new { AssetId = (UInt160)p.AssetId, Account = p.ScriptHash }, (k, g) => new { k.AssetId, Value = g.Aggregate(BigInteger.Zero, (x, y) => x + y.Value.Value), k.Account }).ToArray(); if (cOutputs.Length == 0) { return(null); } var nep5Balances = await TransactionBuilderHelper.GetNep5Balances(AddressScriptHash.ToAddress(), _restService); using (ScriptBuilder sb = new ScriptBuilder()) { foreach (var output in cOutputs) { var nep5Balance = nep5Balances.SingleOrDefault(x => x.AssetHash == output.AssetId.ToString().Remove(0, 2)); if (nep5Balance == null) { throw new WalletException($"Not enough balance of: {output.AssetId} "); } sb.EmitAppCall(output.AssetId, Nep5Methods.transfer.ToString(), AddressScriptHash, output.Account, output.Value); sb.Emit(OpCode.THROWIFNOT); } byte[] nonce = GenerateNonce(8); sb.Emit(OpCode.RET, nonce); tx = new InvocationTransaction { Version = 1, Script = sb.ToArray() }; } if (attributes == null) { attributes = new List <TransactionAttribute>(); } attributes.Add(new TransactionAttribute { Usage = TransactionAttributeUsage.Script, Data = AddressScriptHash.ToArray() }); tx.Attributes = attributes.ToArray(); tx.Inputs = new CoinReference[0]; tx.Outputs = outputs.Where(p => p.IsGlobalAsset).Select(p => p.ToTxOutput()).ToArray(); tx.Witnesses = new Witness[0]; var gasConsumed = await EstimateGasAsync(tx.Script.ToHexString()); //todo add gas limit tx.Gas = InvocationTransaction.GetGas(Fixed8.FromDecimal(gasConsumed)); tx = MakeTransaction(tx, AddressScriptHash, changeAddress, Fixed8.FromDecimal(fee)); var success = await SignAndSendTransaction(tx); return(success ? tx : null); }
//Transfer NEP-5 Asset public static Transaction CreateNep5Transfer(SignDelegate sign) { var from = "AS8UDW7aLhrywLVHFL3ny5tSBaVhWTeZjT".ToScriptHash(); var assetId = new UInt160("ceab719b8baa2310f232ee0d277c061704541cfb".HexToBytes().Reverse().ToArray()); var to = "AS8UDW7aLhrywLVHFL3ny5tSBaVhWTeZjT".ToScriptHash(); var value = 100; //交易输入是 1 GAS var inputs = new List <CoinReference> { //coin reference A new CoinReference() { PrevHash = new UInt256("0x51ac4f7f1662d8c9379ccce3fa7cd2085b9a865edfa53ad892352a41768dd1de".Remove(0, 2).HexToBytes().Reverse().ToArray()), PrevIndex = 0 } }.ToArray(); //交易输出是 0.999 GAS,找回到原地址 var outputs = new List <TransactionOutput> { new TransactionOutput() { AssetId = Blockchain.UtilityToken.Hash, //Asset Id, this is NEO ScriptHash = "AJd31a8rYPEBkY1QSxpsGy8mdU4vTYTD4U".ToScriptHash(), //Receiver Value = new Fixed8((long)(0.999 * (long)Math.Pow(10, 8))) //Value (satoshi unit) } }.ToArray(); //则手续费是 0.001 GAS //Query Balances using (ScriptBuilder sb2 = new ScriptBuilder()) { byte[] script; sb2.EmitAppCall(assetId, "balanceOf", from); sb2.Emit(OpCode.DEPTH, OpCode.PACK); script = sb2.ToArray(); ApplicationEngine engine = ApplicationEngine.Run(script); if (engine.State.HasFlag(VMState.FAULT)) { return(null); } var balances = ((VMArray)engine.ResultStack.Pop())[0]; BigInteger sum = balances.GetBigInteger(); if (sum < value) { Console.WriteLine("Insufficient balance"); return(null); } } //Transfer using (ScriptBuilder sb = new ScriptBuilder()) { sb.EmitAppCall(assetId, "transfer", from, to, value); sb.Emit(OpCode.THROWIFNOT); byte[] nonce = new byte[8]; Random rand = new Random(); rand.NextBytes(nonce); sb.Emit(OpCode.RET, nonce); var tx = new InvocationTransaction { Version = 1, Script = sb.ToArray(), Outputs = outputs, Inputs = inputs, Attributes = new TransactionAttribute[0], Witnesses = new Witness[0] }; return(sign.Invoke(tx)); } }
Result.GetVarSize(); //Result static OracleResponse() { using ScriptBuilder sb = new ScriptBuilder(); sb.EmitAppCall(NativeContract.Oracle.Hash, "finish"); FixedScript = sb.ToArray(); }
public void OnPersist(Snapshot snapshot, IReadOnlyList <Blockchain.ApplicationExecuted> applicationExecutedList) { // Start freshly with a new DBCache for each block. ResetBatch(); Dictionary <Nep5BalanceKey, Nep5Balance> nep5BalancesChanged = new Dictionary <Nep5BalanceKey, Nep5Balance>(); ushort transferIndex = 0; foreach (Blockchain.ApplicationExecuted appExecuted in applicationExecutedList) { // Executions that fault won't modify storage, so we can skip them. if (appExecuted.VMState.HasFlag(VMState.FAULT)) { continue; } foreach (var notifyEventArgs in appExecuted.Notifications) { if (!(notifyEventArgs?.State is VM.Types.Array stateItems) || stateItems.Count == 0 || !(notifyEventArgs.ScriptContainer is Transaction transaction)) { continue; } HandleNotification(snapshot, transaction, notifyEventArgs.ScriptHash, stateItems, nep5BalancesChanged, ref transferIndex); } } foreach (var nep5BalancePair in nep5BalancesChanged) { // get guarantee accurate balances by calling balanceOf for keys that changed. byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { sb.EmitAppCall(nep5BalancePair.Key.AssetScriptHash, "balanceOf", nep5BalancePair.Key.UserScriptHash.ToArray()); script = sb.ToArray(); } ApplicationEngine engine = ApplicationEngine.Run(script, snapshot); if (engine.State.HasFlag(VMState.FAULT)) { continue; } if (engine.ResultStack.Count <= 0) { continue; } nep5BalancePair.Value.Balance = engine.ResultStack.Pop().GetBigInteger(); nep5BalancePair.Value.LastUpdatedBlock = snapshot.Height; if (nep5BalancePair.Value.Balance == 0) { _balances.Delete(nep5BalancePair.Key); continue; } var itemToChange = _balances.GetAndChange(nep5BalancePair.Key, () => nep5BalancePair.Value); if (itemToChange != nep5BalancePair.Value) { itemToChange.FromReplica(nep5BalancePair.Value); } } }
internal static bool VerifyScripts(this IVerifiable verifiable) { const int max_steps = 1200; UInt160[] hashes; try { hashes = verifiable.GetScriptHashesForVerifying(); } catch (InvalidOperationException) { return(false); } if (hashes.Length != verifiable.Scripts.Length) { return(false); } for (int i = 0; i < hashes.Length; i++) { byte[] verification = verifiable.Scripts[i].VerificationScript; if (verification.Length == 0) { using (ScriptBuilder sb = new ScriptBuilder()) { sb.EmitAppCall(hashes[i].ToArray()); verification = sb.ToArray(); } } else { if (hashes[i] != verification.ToScriptHash()) { return(false); } } int nOpCount = 0; ExecutionEngine engine = new ExecutionEngine(verifiable, Crypto.Default, Blockchain.Default, InterfaceEngine.Default); engine.LoadScript(verification, false); engine.LoadScript(verifiable.Scripts[i].InvocationScript, true); while (!engine.State.HasFlag(VMState.HALT) && !engine.State.HasFlag(VMState.FAULT)) { if (engine.CurrentContext.InstructionPointer < engine.CurrentContext.Script.Length) { if (++nOpCount > max_steps) { return(false); } if (engine.CurrentContext.NextInstruction == OpCode.CHECKMULTISIG) { if (engine.EvaluationStack.Count == 0) { return(false); } int n = (int)engine.EvaluationStack.Peek().GetBigInteger(); if (n < 1) { return(false); } nOpCount += n; if (nOpCount > max_steps) { return(false); } } } engine.StepInto(); } if (engine.State.HasFlag(VMState.FAULT)) { return(false); } if (engine.EvaluationStack.Count != 1 || !engine.EvaluationStack.Pop().GetBoolean()) { return(false); } } return(true); }
public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() { var wallet = TestUtils.GenerateTestWallet(); var snapshot = store.GetSnapshot(); // no password on this wallet using (var unlock = wallet.Unlock("")) { var acc = wallet.CreateAccount(); // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem { Value = new Nep5AccountState().ToByteArray() }); entry.Value = new Nep5AccountState() { Balance = 10000 * NativeContract.GAS.Factor } .ToByteArray(); // Make transaction // Manually creating script byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { // self-transfer of 1e-8 GAS System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value; sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value); sb.Emit(OpCode.THROWIFNOT); script = sb.ToArray(); } // trying two custom hashes, for same target account var cosigners = new Cosigner[] { new Cosigner { Account = acc.ScriptHash, Scopes = WitnessScope.CustomContracts, AllowedContracts = new[] { NativeContract.NEO.Hash, NativeContract.GAS.Hash } } }; // using this... var tx = wallet.MakeTransaction(script, acc.ScriptHash, new TransactionAttribute[0], cosigners); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); // ---- // Sign // ---- var data = new ContractParametersContext(tx); bool signed = wallet.Sign(data); Assert.IsTrue(signed); // get witnesses from signed 'data' tx.Witnesses = data.GetWitnesses(); // only a single witness should exist tx.Witnesses.Length.Should().Be(1); // no attributes must exist tx.Attributes.Length.Should().Be(0); // one cosigner must exist tx.Cosigners.Length.Should().Be(1); // Fast check Assert.IsTrue(tx.VerifyWitnesses(snapshot, tx.NetworkFee)); // Check long verificationGas = 0; foreach (var witness in tx.Witnesses) { using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) { engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); Assert.IsTrue(engine.ResultStack.Pop().ToBoolean()); verificationGas += engine.GasConsumed; } } // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); // final check on sum: verification_cost + tx_size Assert.AreEqual(verificationGas + sizeGas, 1299270); // final assert Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas); } }
private bool OnInvokeCommand(string[] args) { var scriptHash = UInt160.Parse(args[1]); List <ContractParameter> contractParameters = new List <ContractParameter>(); for (int i = 3; i < args.Length; i++) { contractParameters.Add(new ContractParameter() { // TODO: support contract params of type other than string. Type = ContractParameterType.String, Value = args[i] }); } Transaction tx = new Transaction { Sender = UInt160.Zero, Attributes = new TransactionAttribute[0], Witness = new Witness { InvocationScript = new byte[0], VerificationScript = new byte[0] } }; using (ScriptBuilder scriptBuilder = new ScriptBuilder()) { scriptBuilder.EmitAppCall(scriptHash, args[2], contractParameters.ToArray()); tx.Script = scriptBuilder.ToArray(); Console.WriteLine($"Invoking script with: '{tx.Script.ToHexString()}'"); } ApplicationEngine engine = ApplicationEngine.Run(tx.Script, tx); Console.WriteLine($"VM State: {engine.State}"); Console.WriteLine($"Gas Consumed: {engine.GasConsumed}"); Console.WriteLine($"Evaluation Stack: {new JArray(engine.ResultStack.Select(p => p.ToParameter().ToJson()))}"); Console.WriteLine(); if (engine.State.HasFlag(VMState.FAULT)) { Console.WriteLine("Engine faulted."); return(true); } if (NoWallet()) { return(true); } try { Program.Wallet.FillTransaction(tx); } catch (InvalidOperationException) { Console.WriteLine("Error: insufficient balance."); return(true); } if (ReadUserInput("relay tx(no|yes)") != "yes") { return(true); } return(SignAndSendTx(tx)); }
public decimal GetBalanceOf(string contract, string address) { // // Console.WriteLine("OnPersist script GetBalanceOf contract 1 {0}", contract); // // Console.WriteLine("OnPersist script GetBalanceOf address 2 {0}", address); UInt160 script_hash = UInt160.Parse(contract); string operation = "balanceOf"; byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { // var paramas = new JArray(); // var paramas = new ContractParameter[1]; // paramas[0].Type =ContractParameterType.Hash160; // paramas[0].Value = address; // paramas.Add(c); var obj = new JObject(); obj["type"] = "Hash160"; obj["value"] = new UInt160(address.HexToBytes()).ToString(); // Console.WriteLine("OnPersist script GetBalanceOf obj 3 {0}", obj.ToString()); var arr = new JArray(); arr.Add(obj); ContractParameter[] parameters = (arr).Select(p => ContractParameter.FromJson(p)).ToArray(); script = sb.EmitAppCall(script_hash, operation, parameters).ToArray(); } ApplicationEngine engine = ApplicationEngine.Run(script, extraGAS: default(Fixed8)); var stack = new JArray(engine.ResultStack.Select(p => p.ToParameter().ToJson())); if (stack.Count == 0) { return(0); } // Console.WriteLine("OnPersist script GetBalanceOf obj 4 {0}", stack.ToString()); // // Console.WriteLine("OnPersist script GetBalanceOf 5 {0}", stack[0]["value"].ToString()); if (stack[0]["value"].AsString() == "") { return(0); } // return 1; // return int.Parse(stack[0]["value"].AsString()); var de = GetDecimals(contract); if (stack[0]["type"].AsString() == "ByteArray" && !string.IsNullOrEmpty(stack[0]["value"].AsString())) { var handleValue = ((new BigInteger(stack[0]["value"].AsString().HexToBytes())) / new BigInteger(Math.Pow(10, de ))); // var handleValue = ((new BigInteger("00ac23fc06".HexToBytes())) / // new BigInteger(Math.Pow(10, GetDecimals()))); // Console.WriteLine("OnPersist script GetBalanceOf 5 {0}", // decimal.Parse(handleValue.ToString(), NumberStyles.Any)); return(decimal.Parse(handleValue.ToString(), NumberStyles.Any)); } if (stack[0]["type"].AsString() == "Integer" && !string.IsNullOrEmpty(stack[0]["value"].AsString())) { var handleValue = (Double.Parse(stack[0]["value"].AsString()) / Math.Pow(10, de)); return(decimal.Parse(handleValue.ToString(), NumberStyles.Any)); } return(0); }
async Task test_mintTokens() { decimal amount = 0; while (true) { subPrintLine("Input amount:"); string str_amount = Console.ReadLine(); try { amount = decimal.Parse(str_amount); break; } catch (Exception e) { subPrintLine("input number"); } } //获取地址的资产列表 Dictionary <string, List <Utxo> > dir = await Helper.GetBalanceByAddress(Config.api, address); if (dir.ContainsKey(Config.id_GAS) == false) { subPrintLine("no gas"); return; } Transaction tran = null; { byte[] script = null; using (var sb = new ScriptBuilder()) { var array = new MyJson.JsonNode_Array(); sb.EmitParamJson(array); //参数倒序入 sb.EmitParamJson(new MyJson.JsonNode_ValueString("(str)mintTokens")); //参数倒序入 Hash160 shash = Config.dapp_sgas; sb.EmitAppCall(shash); //nep5脚本 script = sb.ToArray(); } var sgasScripthash = Config.dapp_sgas; var targetaddr = ThinNeo.Helper.GetAddressFromScriptHash(sgasScripthash); subPrintLine("contract address=" + targetaddr);//往合约地址转账 //生成交易 tran = Helper.makeTran(dir[Config.id_GAS], targetaddr, new Hash256(Config.id_GAS), amount); tran.type = TransactionType.InvocationTransaction; var idata = new InvokeTransData(); tran.extdata = idata; idata.script = script; //sign and broadcast var signdata = ThinNeo.Helper.Sign(tran.GetMessage(), prikey); tran.AddWitness(signdata, pubkey, address); var trandata = tran.GetRawData(); var strtrandata = ThinNeo.Helper.Bytes2HexString(trandata); byte[] postdata; var url = Helper.MakeRpcUrlPost(Config.api, "sendrawtransaction", out postdata, new MyJson.JsonNode_ValueString(strtrandata)); var result = await Helper.HttpPost(url, postdata); subPrintLine("得到的结果是:" + result); var json = MyJson.Parse(result).AsDict(); if (json.ContainsKey("result")) { var resultv = json["result"].AsList()[0].AsDict(); var txid = resultv["txid"].AsString(); subPrintLine("txid=" + txid); } } }
private JObject Process(string method, JArray _params) { switch (method) { case "dumpprivkey": if (wallet == null) { throw new RpcException(-400, "Access denied"); } else { UInt160 scriptHash = _params[0].AsString().ToScriptHash(); WalletAccount account = wallet.GetAccount(scriptHash); return(account.GetKey().Export()); } case "getaccountstate": { UInt160 script_hash = _params[0].AsString().ToScriptHash(); AccountState account = Blockchain.Singleton.Store.GetAccounts().TryGet(script_hash) ?? new AccountState(script_hash); return(account.ToJson()); } case "getassetstate": { UInt256 asset_id = UInt256.Parse(_params[0].AsString()); AssetState asset = Blockchain.Singleton.Store.GetAssets().TryGet(asset_id); return(asset?.ToJson() ?? throw new RpcException(-100, "Unknown asset")); } case "getbalance": if (wallet == null) { throw new RpcException(-400, "Access denied."); } else { JObject json = new JObject(); switch (UIntBase.Parse(_params[0].AsString())) { case UInt160 asset_id_160: //NEP-5 balance json["balance"] = wallet.GetAvailable(asset_id_160).ToString(); break; case UInt256 asset_id_256: //Global Assets balance IEnumerable <Coin> coins = wallet.GetCoins().Where(p => !p.State.HasFlag(CoinState.Spent) && p.Output.AssetId.Equals(asset_id_256)); json["balance"] = coins.Sum(p => p.Output.Value).ToString(); json["confirmed"] = coins.Where(p => p.State.HasFlag(CoinState.Confirmed)).Sum(p => p.Output.Value).ToString(); break; } return(json); } case "getbestblockhash": return(Blockchain.Singleton.CurrentBlockHash.ToString()); case "getblock": { Block block; if (_params[0] is JNumber) { uint index = (uint)_params[0].AsNumber(); block = Blockchain.Singleton.Store.GetBlock(index); } else { UInt256 hash = UInt256.Parse(_params[0].AsString()); block = Blockchain.Singleton.Store.GetBlock(hash); } if (block == null) { throw new RpcException(-100, "Unknown block"); } bool verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false); if (verbose) { JObject json = block.ToJson(); json["confirmations"] = Blockchain.Singleton.Height - block.Index + 1; UInt256 hash = Blockchain.Singleton.Store.GetNextBlockHash(block.Hash); if (hash != null) { json["nextblockhash"] = hash.ToString(); } return(json); } return(block.ToArray().ToHexString()); } case "getblockcount": return(Blockchain.Singleton.Height + 1); case "getblockhash": { uint height = (uint)_params[0].AsNumber(); if (height <= Blockchain.Singleton.Height) { return(Blockchain.Singleton.GetBlockHash(height).ToString()); } throw new RpcException(-100, "Invalid Height"); } case "getblockheader": { Header header; if (_params[0] is JNumber) { uint height = (uint)_params[0].AsNumber(); header = Blockchain.Singleton.Store.GetHeader(height); } else { UInt256 hash = UInt256.Parse(_params[0].AsString()); header = Blockchain.Singleton.Store.GetHeader(hash); } if (header == null) { throw new RpcException(-100, "Unknown block"); } bool verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false); if (verbose) { JObject json = header.ToJson(); json["confirmations"] = Blockchain.Singleton.Height - header.Index + 1; UInt256 hash = Blockchain.Singleton.Store.GetNextBlockHash(header.Hash); if (hash != null) { json["nextblockhash"] = hash.ToString(); } return(json); } return(header.ToArray().ToHexString()); } case "getblocksysfee": { uint height = (uint)_params[0].AsNumber(); if (height <= Blockchain.Singleton.Height) { return(Blockchain.Singleton.Store.GetSysFeeAmount(height).ToString()); } throw new RpcException(-100, "Invalid Height"); } case "getconnectioncount": return(LocalNode.Singleton.ConnectedCount); case "getcontractstate": { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); ContractState contract = Blockchain.Singleton.Store.GetContracts().TryGet(script_hash); return(contract?.ToJson() ?? throw new RpcException(-100, "Unknown contract")); } case "getnewaddress": if (wallet == null) { throw new RpcException(-400, "Access denied"); } else { WalletAccount account = wallet.CreateAccount(); if (wallet is TERC1Wallet nep6) { nep6.Save(); } return(account.Address); } case "getpeers": { JObject json = new JObject(); json["unconnected"] = new JArray(LocalNode.Singleton.GetUnconnectedPeers().Select(p => { JObject peerJson = new JObject(); peerJson["address"] = p.Address.ToString(); peerJson["port"] = p.Port; return(peerJson); })); json["bad"] = new JArray(); //badpeers has been removed json["connected"] = new JArray(LocalNode.Singleton.GetRemoteNodes().Select(p => { JObject peerJson = new JObject(); peerJson["address"] = p.Remote.Address.ToString(); peerJson["port"] = p.ListenerPort; return(peerJson); })); return(json); } case "getrawmempool": return(new JArray(Blockchain.Singleton.GetMemoryPool().Select(p => (JObject)p.Hash.ToString()))); case "getrawtransaction": { UInt256 hash = UInt256.Parse(_params[0].AsString()); bool verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false); Transaction tx = Blockchain.Singleton.GetTransaction(hash); if (tx == null) { throw new RpcException(-100, "Unknown transaction"); } if (verbose) { JObject json = tx.ToJson(); uint? height = Blockchain.Singleton.Store.GetTransactions().TryGet(hash)?.BlockIndex; if (height != null) { Header header = Blockchain.Singleton.Store.GetHeader((uint)height); json["blockhash"] = header.Hash.ToString(); json["confirmations"] = Blockchain.Singleton.Height - header.Index + 1; json["blocktime"] = header.Timestamp; } return(json); } return(tx.ToArray().ToHexString()); } case "getstorage": { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); byte[] key = _params[1].AsString().HexToBytes(); StorageItem item = Blockchain.Singleton.Store.GetStorages().TryGet(new StorageKey { ScriptHash = script_hash, Key = key }) ?? new StorageItem(); return(item.Value?.ToHexString()); } case "gettxout": { UInt256 hash = UInt256.Parse(_params[0].AsString()); ushort index = (ushort)_params[1].AsNumber(); return(Blockchain.Singleton.Store.GetUnspent(hash, index)?.ToJson(index)); } case "getvalidators": using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) { var validators = snapshot.GetValidators(); return(snapshot.GetEnrollments().Select(p => { JObject validator = new JObject(); validator["publickey"] = p.PublicKey.ToString(); validator["votes"] = p.Votes.ToString(); validator["active"] = validators.Contains(p.PublicKey); return validator; }).ToArray()); } case "getversion": { JObject json = new JObject(); json["port"] = LocalNode.Singleton.ListenerPort; json["nonce"] = LocalNode.Nonce; json["useragent"] = LocalNode.UserAgent; return(json); } case "getwalletheight": if (wallet == null) { throw new RpcException(-400, "Access denied."); } else { return((wallet.WalletHeight > 0) ? wallet.WalletHeight - 1 : 0); } case "invoke": { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); ContractParameter[] parameters = ((JArray)_params[1]).Select(p => ContractParameter.FromJson(p)).ToArray(); byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { script = sb.EmitAppCall(script_hash, parameters).ToArray(); } return(GetInvokeResult(script)); } case "invokefunction": { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); string operation = _params[1].AsString(); ContractParameter[] args = _params.Count >= 3 ? ((JArray)_params[2]).Select(p => ContractParameter.FromJson(p)).ToArray() : new ContractParameter[0]; byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { script = sb.EmitAppCall(script_hash, operation, args).ToArray(); } return(GetInvokeResult(script)); } case "invokescript": { byte[] script = _params[0].AsString().HexToBytes(); return(GetInvokeResult(script)); } case "listaddress": if (wallet == null) { throw new RpcException(-400, "Access denied."); } else { return(wallet.GetAccounts().Select(p => { JObject account = new JObject(); account["address"] = p.Address; account["haskey"] = p.HasKey; account["label"] = p.Label; account["watchonly"] = p.WatchOnly; return account; }).ToArray()); } case "sendfrom": if (wallet == null) { throw new RpcException(-400, "Access denied"); } else { UIntBase assetId = UIntBase.Parse(_params[0].AsString()); AssetDescriptor descriptor = new AssetDescriptor(assetId); UInt160 from = _params[1].AsString().ToScriptHash(); UInt160 to = _params[2].AsString().ToScriptHash(); BigDecimal value = BigDecimal.Parse(_params[3].AsString(), descriptor.Decimals); if (value.Sign <= 0) { throw new RpcException(-32602, "Invalid params"); } Fixed8 fee = _params.Count >= 5 ? Fixed8.Parse(_params[4].AsString()) : Fixed8.Zero; if (fee < Fixed8.Zero) { throw new RpcException(-32602, "Invalid params"); } UInt160 change_address = _params.Count >= 6 ? _params[5].AsString().ToScriptHash() : null; Transaction tx = wallet.MakeTransaction(null, new[] { new TransferOutput { AssetId = assetId, Value = value, ScriptHash = to } }, from: from, change_address: change_address, fee: fee); if (tx == null) { throw new RpcException(-300, "Insufficient funds"); } ContractParametersContext context = new ContractParametersContext(tx); wallet.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); wallet.ApplyTransaction(tx); system.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); return(tx.ToJson()); } else { return(context.ToJson()); } } case "sendmany": if (wallet == null) { throw new RpcException(-400, "Access denied"); } else { JArray to = (JArray)_params[0]; if (to.Count == 0) { throw new RpcException(-32602, "Invalid params"); } TransferOutput[] outputs = new TransferOutput[to.Count]; for (int i = 0; i < to.Count; i++) { UIntBase asset_id = UIntBase.Parse(to[i]["asset"].AsString()); AssetDescriptor descriptor = new AssetDescriptor(asset_id); outputs[i] = new TransferOutput { AssetId = asset_id, Value = BigDecimal.Parse(to[i]["value"].AsString(), descriptor.Decimals), ScriptHash = to[i]["address"].AsString().ToScriptHash() }; if (outputs[i].Value.Sign <= 0) { throw new RpcException(-32602, "Invalid params"); } } Fixed8 fee = _params.Count >= 2 ? Fixed8.Parse(_params[1].AsString()) : Fixed8.Zero; if (fee < Fixed8.Zero) { throw new RpcException(-32602, "Invalid params"); } UInt160 change_address = _params.Count >= 3 ? _params[2].AsString().ToScriptHash() : null; Transaction tx = wallet.MakeTransaction(null, outputs, change_address: change_address, fee: fee); if (tx == null) { throw new RpcException(-300, "Insufficient funds"); } ContractParametersContext context = new ContractParametersContext(tx); wallet.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); wallet.ApplyTransaction(tx); system.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); return(tx.ToJson()); } else { return(context.ToJson()); } } case "sendrawtransaction": { Transaction tx = Transaction.DeserializeFrom(_params[0].AsString().HexToBytes()); RelayResultReason reason = system.Blockchain.Ask <RelayResultReason>(tx).Result; return(GetRelayResult(reason)); } case "sendtoaddress": if (wallet == null) { throw new RpcException(-400, "Access denied"); } else { UIntBase assetId = UIntBase.Parse(_params[0].AsString()); AssetDescriptor descriptor = new AssetDescriptor(assetId); UInt160 scriptHash = _params[1].AsString().ToScriptHash(); BigDecimal value = BigDecimal.Parse(_params[2].AsString(), descriptor.Decimals); if (value.Sign <= 0) { throw new RpcException(-32602, "Invalid params"); } Fixed8 fee = _params.Count >= 4 ? Fixed8.Parse(_params[3].AsString()) : Fixed8.Zero; if (fee < Fixed8.Zero) { throw new RpcException(-32602, "Invalid params"); } UInt160 change_address = _params.Count >= 5 ? _params[4].AsString().ToScriptHash() : null; Transaction tx = wallet.MakeTransaction(null, new[] { new TransferOutput { AssetId = assetId, Value = value, ScriptHash = scriptHash } }, change_address: change_address, fee: fee); if (tx == null) { throw new RpcException(-300, "Insufficient funds"); } ContractParametersContext context = new ContractParametersContext(tx); wallet.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); wallet.ApplyTransaction(tx); system.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); return(tx.ToJson()); } else { return(context.ToJson()); } } case "submitblock": { Block block = _params[0].AsString().HexToBytes().AsSerializable <Block>(); RelayResultReason reason = system.Blockchain.Ask <RelayResultReason>(block).Result; return(GetRelayResult(reason)); } case "validateaddress": { JObject json = new JObject(); UInt160 scriptHash; try { scriptHash = _params[0].AsString().ToScriptHash(); } catch { scriptHash = null; } json["address"] = _params[0]; json["isvalid"] = scriptHash != null; return(json); } default: throw new RpcException(-32601, "Method not found"); } }
public Transaction GetTransaction() { var cOutputs = txOutListBox1.Items.Where(p => p.AssetId is UInt160).GroupBy(p => new { AssetId = (UInt160)p.AssetId, Account = p.ScriptHash }, (k, g) => new { k.AssetId, Value = g.Aggregate(BigInteger.Zero, (x, y) => x + y.Value.Value), k.Account }).ToArray(); Transaction tx; List <TransactionAttribute> attributes = new List <TransactionAttribute>(); if (comboBoxFrom.SelectedItem == null) { FromAddress = null; } else { FromAddress = ((string)comboBoxFrom.SelectedItem).ToScriptHash(); } if (cOutputs.Length == 0) { tx = new ContractTransaction(); } else { UInt160[] addresses; if (FromAddress != null) { addresses = Program.CurrentWallet.GetAccounts().Where(e => e.ScriptHash.Equals(FromAddress)).Select(p => p.ScriptHash).ToArray(); } else { addresses = Program.CurrentWallet.GetAccounts().Where(e => !e.WatchOnly).Select(p => p.ScriptHash).ToArray(); } HashSet <UInt160> sAttributes = new HashSet <UInt160>(); using (ScriptBuilder sb = new ScriptBuilder()) { foreach (var output in cOutputs) { byte[] script; using (ScriptBuilder sb2 = new ScriptBuilder()) { foreach (UInt160 address in addresses) { sb2.EmitAppCall(output.AssetId, "balanceOf", address); } sb2.Emit(OpCode.DEPTH, OpCode.PACK); script = sb2.ToArray(); } ApplicationEngine engine = ApplicationEngine.Run(script); if (engine.State.HasFlag(VMState.FAULT)) { return(null); } var balances = ((VMArray)engine.ResultStack.Pop()).AsEnumerable().Reverse().Zip(addresses, (i, a) => new { Account = a, Value = i.GetBigInteger() }).Where(p => p.Value != 0).ToArray(); BigInteger sum = balances.Aggregate(BigInteger.Zero, (x, y) => x + y.Value); if (sum < output.Value) { return(null); } if (sum != output.Value) { balances = balances.OrderByDescending(p => p.Value).ToArray(); BigInteger amount = output.Value; int i = 0; while (balances[i].Value <= amount) { amount -= balances[i++].Value; } if (amount == BigInteger.Zero) { balances = balances.Take(i).ToArray(); } else { balances = balances.Take(i).Concat(new[] { balances.Last(p => p.Value >= amount) }).ToArray(); } sum = balances.Aggregate(BigInteger.Zero, (x, y) => x + y.Value); } sAttributes.UnionWith(balances.Select(p => p.Account)); for (int i = 0; i < balances.Length; i++) { BigInteger value = balances[i].Value; if (i == 0) { BigInteger change = sum - output.Value; if (change > 0) { value -= change; } } sb.EmitAppCall(output.AssetId, "transfer", balances[i].Account, output.Account, value); sb.Emit(OpCode.THROWIFNOT); } } tx = new InvocationTransaction { Version = 1, Script = sb.ToArray() }; } attributes.AddRange(sAttributes.Select(p => new TransactionAttribute { Usage = TransactionAttributeUsage.Script, Data = p.ToArray() })); } if (!string.IsNullOrEmpty(remark)) { attributes.Add(new TransactionAttribute { Usage = TransactionAttributeUsage.Remark, Data = Encoding.UTF8.GetBytes(remark) }); } tx.Attributes = attributes.ToArray(); tx.Outputs = txOutListBox1.Items.Where(p => p.AssetId is UInt256).Select(p => p.ToTxOutput()).ToArray(); var tempOuts = tx.Outputs; if (tx is ContractTransaction copyTx) { copyTx.Witnesses = new Witness[0]; copyTx = Program.CurrentWallet.MakeTransaction(copyTx, FromAddress, change_address: ChangeAddress, fee: Fee); if (copyTx == null) { return(null); } ContractParametersContext transContext = new ContractParametersContext(copyTx); Program.CurrentWallet.Sign(transContext); if (transContext.Completed) { copyTx.Witnesses = transContext.GetWitnesses(); } if (copyTx.Size > 1024) { Fixed8 PriorityFee = Fixed8.FromDecimal(0.001m) + Fixed8.FromDecimal(copyTx.Size * 0.00001m); if (Fee > PriorityFee) { PriorityFee = Fee; } if (!Helper.CostRemind(Fixed8.Zero, PriorityFee)) { return(null); } tx = Program.CurrentWallet.MakeTransaction(new ContractTransaction { Outputs = tempOuts, Attributes = tx.Attributes }, FromAddress, change_address: ChangeAddress, fee: PriorityFee); } } return(tx); }
public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() { var wallet = TestUtils.GenerateTestWallet(); var snapshot = Blockchain.Singleton.GetSnapshot(); // no password on this wallet using (var unlock = wallet.Unlock("")) { var acc = wallet.CreateAccount(); // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new Nep5AccountState())); entry.GetInteroperable <Nep5AccountState>().Balance = 10000 * NativeContract.GAS.Factor; snapshot.Commit(); // Make transaction // Manually creating script byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { // self-transfer of 1e-8 GAS System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value; sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); } // trying CalledByEntry together with GAS var cosigners = new Cosigner[] { new Cosigner { Account = acc.ScriptHash, // This combination is supposed to actually be an OR, // where it's valid in both Entry and also for Custom hash provided (in any execution level) // it would be better to test this in the future including situations where a deeper call level uses this custom witness successfully Scopes = WitnessScope.CustomContracts | WitnessScope.CalledByEntry, AllowedContracts = new[] { NativeContract.GAS.Hash } } }; // using this... var tx = wallet.MakeTransaction(script, acc.ScriptHash, cosigners); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); // ---- // Sign // ---- var data = new ContractParametersContext(tx); bool signed = wallet.Sign(data); Assert.IsTrue(signed); // get witnesses from signed 'data' tx.Witnesses = data.GetWitnesses(); tx.Witnesses.Length.Should().Be(1); // Fast check Assert.IsTrue(tx.VerifyWitnesses(snapshot, tx.NetworkFee)); // Check long verificationGas = 0; foreach (var witness in tx.Witnesses) { using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) { engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); Assert.IsTrue(engine.ResultStack.Pop().ToBoolean()); verificationGas += engine.GasConsumed; } } // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); // final check on sum: verification_cost + tx_size Assert.AreEqual(1285390, verificationGas + sizeGas); // final assert Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas); } }
public void TestParallel() { var args = new ExecutionEngineArgs() { ScriptTable = new DummyScriptTable ( new byte[] { (byte)EVMOpCode.EQUAL }, new byte[] { (byte)EVMOpCode.EQUAL } ) }; // 5 Scripts var engines = new List <ExecutionEngineBase>() { CreateEngine(args), CreateEngine(args), CreateEngine(args), CreateEngine(args), CreateEngine(args), CreateEngine(args), CreateEngine(args), CreateEngine(args), CreateEngine(args), CreateEngine(args) }; Parallel.ForEach(engines, (engine) => { using (engine) { for (ushort x = 0; x < 1000; x++) { // Load script engine.Clean(x); using (var script = new ScriptBuilder()) { script.EmitPush(x); script.EmitPush(x); script.EmitAppCall(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, }); engine.LoadScript(script); } // Execute Assert.IsTrue(engine.Execute()); // Check result using (var it = engine.ResultStack.Pop <BooleanStackItem>()) { Assert.IsTrue(it.Value); } } } }); }
private void timer1_Tick(object sender, EventArgs e) { lbl_height.Text = $"{Blockchain.Singleton.Height}/{Blockchain.Singleton.HeaderHeight}"; lbl_count_node.Text = LocalNode.Singleton.ConnectedCount.ToString(); TimeSpan persistence_span = DateTime.UtcNow - persistence_time; if (persistence_span < TimeSpan.Zero) { persistence_span = TimeSpan.Zero; } if (persistence_span > Blockchain.TimePerBlock) { toolStripProgressBar1.Style = ProgressBarStyle.Marquee; } else { toolStripProgressBar1.Value = persistence_span.Seconds; toolStripProgressBar1.Style = ProgressBarStyle.Blocks; } if (Service.CurrentWallet is null) { return; } if (!check_nep5_balance || persistence_span < TimeSpan.FromSeconds(2)) { return; } check_nep5_balance = false; UInt160[] addresses = Service.CurrentWallet.GetAccounts().Select(p => p.ScriptHash).ToArray(); if (addresses.Length == 0) { return; } using SnapshotView snapshot = Blockchain.Singleton.GetSnapshot(); foreach (UInt160 assetId in NEP5Watched) { byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { for (int i = addresses.Length - 1; i >= 0; i--) { sb.EmitAppCall(assetId, "balanceOf", addresses[i]); } sb.Emit(OpCode.DEPTH, OpCode.PACK); sb.EmitAppCall(assetId, "decimals"); sb.EmitAppCall(assetId, "name"); script = sb.ToArray(); } using ApplicationEngine engine = ApplicationEngine.Run(script, snapshot, extraGAS: 0_20000000L * addresses.Length); if (engine.State.HasFlag(VMState.FAULT)) { continue; } string name = engine.ResultStack.Pop().GetString(); byte decimals = (byte)engine.ResultStack.Pop().GetBigInteger(); BigInteger[] balances = ((VMArray)engine.ResultStack.Pop()).Select(p => p.GetBigInteger()).ToArray(); string symbol = null; if (assetId.Equals(NativeContract.NEO.Hash)) { symbol = NativeContract.NEO.Symbol; } else if (assetId.Equals(NativeContract.GAS.Hash)) { symbol = NativeContract.GAS.Symbol; } if (symbol != null) { for (int i = 0; i < addresses.Length; i++) { listView1.Items[addresses[i].ToAddress()].SubItems[symbol].Text = new BigDecimal(balances[i], decimals).ToString(); } } BigInteger amount = balances.Sum(); if (amount == 0) { listView2.Items.RemoveByKey(assetId.ToString()); continue; } BigDecimal balance = new BigDecimal(amount, decimals); if (listView2.Items.ContainsKey(assetId.ToString())) { listView2.Items[assetId.ToString()].SubItems["value"].Text = balance.ToString(); } else { listView2.Items.Add(new ListViewItem(new[] { new ListViewItem.ListViewSubItem { Name = "name", Text = name }, new ListViewItem.ListViewSubItem { Name = "type", Text = "NEP-5" }, new ListViewItem.ListViewSubItem { Name = "value", Text = balance.ToString() }, new ListViewItem.ListViewSubItem { ForeColor = Color.Gray, Name = "issuer", Text = $"ScriptHash:{assetId}" } }, -1) { Name = assetId.ToString(), UseItemStyleForSubItems = false }); } } }
public void Runtime_GetNotifications_Test() { UInt160 scriptHash2; var snapshot = Blockchain.Singleton.GetSnapshot(); using (var script = new ScriptBuilder()) { // Notify method script.Emit(OpCode.SWAP, OpCode.NEWARRAY, OpCode.SWAP); script.EmitSysCall(ApplicationEngine.System_Runtime_Notify); // Add return script.EmitPush(true); script.Emit(OpCode.RET); // Mock contract scriptHash2 = script.ToArray().ToScriptHash(); snapshot.Contracts.Delete(scriptHash2); snapshot.Contracts.Add(scriptHash2, new ContractState() { Script = script.ToArray(), Manifest = TestUtils.CreateManifest(scriptHash2, "test", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer), }); } // Wrong length using (var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true)) using (var script = new ScriptBuilder()) { // Retrive script.EmitPush(1); script.EmitSysCall(ApplicationEngine.System_Runtime_GetNotifications); // Execute engine.LoadScript(script.ToArray()); Assert.AreEqual(VMState.FAULT, engine.Execute()); } // All test using (var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true)) using (var script = new ScriptBuilder()) { // Notification script.EmitPush(0); script.Emit(OpCode.NEWARRAY); script.EmitPush("testEvent1"); script.EmitSysCall(ApplicationEngine.System_Runtime_Notify); // Call script script.EmitAppCall(scriptHash2, ContractParameterType.Any, "test", "testEvent2", 1); // Drop return script.Emit(OpCode.DROP); // Receive all notifications script.Emit(OpCode.PUSHNULL); script.EmitSysCall(ApplicationEngine.System_Runtime_GetNotifications); // Execute engine.LoadScript(script.ToArray()); var currentScriptHash = engine.EntryScriptHash; Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); Assert.AreEqual(2, engine.Notifications.Count); Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(VM.Types.Array)); var array = (VM.Types.Array)engine.ResultStack.Pop(); // Check syscall result AssertNotification(array[1], scriptHash2, "testEvent2"); AssertNotification(array[0], currentScriptHash, "testEvent1"); // Check notifications Assert.AreEqual(scriptHash2, engine.Notifications[1].ScriptHash); Assert.AreEqual("testEvent2", engine.Notifications[1].EventName); Assert.AreEqual(currentScriptHash, engine.Notifications[0].ScriptHash); Assert.AreEqual("testEvent1", engine.Notifications[0].EventName); } // Script notifications using (var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true)) using (var script = new ScriptBuilder()) { // Notification script.EmitPush(0); script.Emit(OpCode.NEWARRAY); script.EmitPush("testEvent1"); script.EmitSysCall(ApplicationEngine.System_Runtime_Notify); // Call script script.EmitAppCall(scriptHash2, ContractParameterType.Any, "test", "testEvent2", 1); // Drop return script.Emit(OpCode.DROP); // Receive all notifications script.EmitPush(scriptHash2.ToArray()); script.EmitSysCall(ApplicationEngine.System_Runtime_GetNotifications); // Execute engine.LoadScript(script.ToArray()); var currentScriptHash = engine.EntryScriptHash; Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); Assert.AreEqual(2, engine.Notifications.Count); Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(VM.Types.Array)); var array = (VM.Types.Array)engine.ResultStack.Pop(); // Check syscall result AssertNotification(array[0], scriptHash2, "testEvent2"); // Check notifications Assert.AreEqual(scriptHash2, engine.Notifications[1].ScriptHash); Assert.AreEqual("testEvent2", engine.Notifications[1].EventName); Assert.AreEqual(currentScriptHash, engine.Notifications[0].ScriptHash); Assert.AreEqual("testEvent1", engine.Notifications[0].EventName); } // Clean storage snapshot.Contracts.Delete(scriptHash2); }
protected virtual JObject Process(string method, JArray _params) { switch (method) { case "getaccountstate": { UInt160 script_hash = Wallet.ToScriptHash(_params[0].AsString()); AccountState account = Blockchain.Default.GetAccountState(script_hash) ?? new AccountState(script_hash); return(account.ToJson()); } case "getassetstate": { UInt256 asset_id = UInt256.Parse(_params[0].AsString()); AssetState asset = Blockchain.Default.GetAssetState(asset_id); return(asset?.ToJson() ?? throw new RpcException(-100, "Unknown asset")); } case "getbestblockhash": return(Blockchain.Default.CurrentBlockHash.ToString()); case "getblock": { Block block; if (_params[0] is JNumber) { uint index = (uint)_params[0].AsNumber(); block = Blockchain.Default.GetBlock(index); } else { UInt256 hash = UInt256.Parse(_params[0].AsString()); block = Blockchain.Default.GetBlock(hash); } if (block == null) { throw new RpcException(-100, "Unknown block"); } bool verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false); if (verbose) { JObject json = block.ToJson(); json["confirmations"] = Blockchain.Default.Height - block.Index + 1; UInt256 hash = Blockchain.Default.GetNextBlockHash(block.Hash); if (hash != null) { json["nextblockhash"] = hash.ToString(); } return(json); } else { return(block.ToArray().ToHexString()); } } case "getblockcount": return(Blockchain.Default.Height + 1); case "getblockhash": { uint height = (uint)_params[0].AsNumber(); if (height >= 0 && height <= Blockchain.Default.Height) { return(Blockchain.Default.GetBlockHash(height).ToString()); } else { throw new RpcException(-100, "Invalid Height"); } } case "getblocksysfee": { uint height = (uint)_params[0].AsNumber(); if (height >= 0 && height <= Blockchain.Default.Height) { return(Blockchain.Default.GetSysFeeAmount(height).ToString()); } else { throw new RpcException(-100, "Invalid Height"); } } case "getconnectioncount": return(LocalNode.RemoteNodeCount); case "getcontractstate": { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); ContractState contract = Blockchain.Default.GetContract(script_hash); return(contract?.ToJson() ?? throw new RpcException(-100, "Unknown contract")); } case "getrawmempool": return(new JArray(LocalNode.GetMemoryPool().Select(p => (JObject)p.Hash.ToString()))); case "getrawtransaction": { UInt256 hash = UInt256.Parse(_params[0].AsString()); bool verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false); int height = -1; Transaction tx = LocalNode.GetTransaction(hash); if (tx == null) { tx = Blockchain.Default.GetTransaction(hash, out height); } if (tx == null) { throw new RpcException(-100, "Unknown transaction"); } if (verbose) { JObject json = tx.ToJson(); if (height >= 0) { Header header = Blockchain.Default.GetHeader((uint)height); json["blockhash"] = header.Hash.ToString(); json["confirmations"] = Blockchain.Default.Height - header.Index + 1; json["blocktime"] = header.Timestamp; } return(json); } else { return(tx.ToArray().ToHexString()); } } case "getstorage": { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); byte[] key = _params[1].AsString().HexToBytes(); StorageItem item = Blockchain.Default.GetStorageItem(new StorageKey { ScriptHash = script_hash, Key = key }) ?? new StorageItem(); return(item.Value?.ToHexString()); } case "gettxout": { UInt256 hash = UInt256.Parse(_params[0].AsString()); ushort index = (ushort)_params[1].AsNumber(); return(Blockchain.Default.GetUnspent(hash, index)?.ToJson(index)); } case "getvalidators": { var validators = Blockchain.Default.GetValidators(); return(Blockchain.Default.GetEnrollments().Select(p => { JObject validator = new JObject(); validator["publickey"] = p.PublicKey.ToString(); validator["votes"] = p.Votes.ToString(); validator["active"] = validators.Contains(p.PublicKey); return validator; }).ToArray()); } case "invoke": { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); ContractParameter[] parameters = ((JArray)_params[1]).Select(p => ContractParameter.FromJson(p)).ToArray(); byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { script = sb.EmitAppCall(script_hash, parameters).ToArray(); } return(GetInvokeResult(script)); } case "invokefunction": { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); string operation = _params[1].AsString(); ContractParameter[] args = _params.Count >= 3 ? ((JArray)_params[2]).Select(p => ContractParameter.FromJson(p)).ToArray() : new ContractParameter[0]; byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { script = sb.EmitAppCall(script_hash, operation, args).ToArray(); } return(GetInvokeResult(script)); } case "invokescript": { byte[] script = _params[0].AsString().HexToBytes(); return(GetInvokeResult(script)); } case "sendrawtransaction": { Transaction tx = Transaction.DeserializeFrom(_params[0].AsString().HexToBytes()); return(LocalNode.Relay(tx)); } case "submitblock": { Block block = _params[0].AsString().HexToBytes().AsSerializable <Block>(); return(LocalNode.Relay(block)); } case "validateaddress": { JObject json = new JObject(); UInt160 scriptHash; try { scriptHash = Wallet.ToScriptHash(_params[0].AsString()); } catch { scriptHash = null; } json["address"] = _params[0]; json["isvalid"] = scriptHash != null; return(json); } case "getpeers": { JObject json = new JObject(); { JArray unconnectedPeers = new JArray(); foreach (IPEndPoint peer in LocalNode.GetUnconnectedPeers()) { JObject peerJson = new JObject(); peerJson["address"] = peer.Address.ToString(); peerJson["port"] = peer.Port; unconnectedPeers.Add(peerJson); } json["unconnected"] = unconnectedPeers; } { JArray badPeers = new JArray(); foreach (IPEndPoint peer in LocalNode.GetBadPeers()) { JObject peerJson = new JObject(); peerJson["address"] = peer.Address.ToString(); peerJson["port"] = peer.Port; badPeers.Add(peerJson); } json["bad"] = badPeers; } { JArray connectedPeers = new JArray(); foreach (RemoteNode node in LocalNode.GetRemoteNodes()) { JObject peerJson = new JObject(); peerJson["address"] = node.RemoteEndpoint.Address.ToString(); peerJson["port"] = node.ListenerEndpoint?.Port ?? 0; connectedPeers.Add(peerJson); } json["connected"] = connectedPeers; } return(json); } case "getversion": { JObject json = new JObject(); json["port"] = LocalNode.Port; json["nonce"] = LocalNode.Nonce; json["useragent"] = LocalNode.UserAgent; return(json); } case "createwallet": { JObject json = new JObject(); return(json); } default: throw new RpcException(-32601, "Method not found"); } }
public void Run() { string wif = "KwwJMvfFPcRx2HSgQRPviLv4wPrxRaLk7kfQntkH8kCXzTgAts8t"; //自己 string targetAddress = "AQye22dcXV1jCrzzC4iGbyM68LADwPSs11"; //别人 string asset = "0x602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"; //币种(GAS转换NNC) decimal sendCount = new decimal(1); byte[] prikey = Helper.GetPrivateKeyFromWIF(wif); byte[] pubkey = Helper.GetPublicKeyFromPrivateKey(prikey); string address = Helper.GetAddressFromPublicKey(pubkey); SQLServer sQLServer = new SQLServer(); sQLServer.Open(); //接收一个读取对象 SqlDataReader reader = sQLServer.GetUTXO(address, asset); //整理utxo Dictionary <string, List <UTXO> > dic_UTXO = GetUTXO(reader); sQLServer.Close(); //拼交易 Transaction transaction = MakeTransaction(dic_UTXO, address, targetAddress, new Hash256(asset), 0); transaction.version = 0; transaction.attributes = new ThinNeo.Attribute[0]; //与普通转账的区别 transaction.type = TransactionType.InvocationTransaction;//调用合约的转账 InvokeTransData invokeTransData = new InvokeTransData(); byte[] script = null; using (ScriptBuilder sb = new ScriptBuilder()) { var array = new MyJson.JsonNode_Array(); array.AddArrayValue("(addr)" + address); //from array.AddArrayValue("(addr)" + targetAddress); //to array.AddArrayValue("(int)" + "1" + "00"); //value sb.EmitParamJson(array); //参数倒序入 sb.EmitPushString("transfer"); //参数倒序入 sb.EmitAppCall(new Hash160("0xbab964febd82c9629cc583596975f51811f25f47")); //合约 script = sb.ToArray(); } invokeTransData.script = script; invokeTransData.gas = 0; transaction.extdata = invokeTransData; /// byte[] msg = transaction.GetMessage(); string msgStr = Helper.Bytes2HexString(msg); byte[] signdata = Helper.Sign(msg, prikey);//签名 transaction.AddWitness(signdata, pubkey, address); string txid = transaction.GetHash().ToString(); byte[] data = transaction.GetRawData(); string rawdata = Helper.Bytes2HexString(data); //广播 HttpRequest httpRequest = new HttpRequest(); JObject jObject = httpRequest.Post("sendrawtransaction", rawdata); string info = jObject.ToString(); Console.WriteLine("NNC" + info); }