private static byte[] calcDigest(Transaction tx, bool needSigns) { string encoded = ""; var settings = new JsonSerializerSettings() { Formatting = Formatting.None, DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, }; if (tx.TxInputs != null) { for (var i = 0; i < tx.TxInputs.Count; i++) { var input = tx.TxInputs[i]; if (input.RefTxid.Length > 0) { encoded += JsonConvert.SerializeObject(input.RefTxid) + "\n"; } encoded += JsonConvert.SerializeObject(input.RefOffset) + "\n"; if (input.FromAddr.Length > 0) { encoded += JsonConvert.SerializeObject(input.FromAddr) + "\n"; } if (input.Amount.Length > 0) { encoded += JsonConvert.SerializeObject(input.Amount) + "\n"; } encoded += JsonConvert.SerializeObject(input.FrozenHeight) + "\n"; } } encoded += JsonConvert.SerializeObject(tx.TxOutputs, settings) + "\n"; if (tx.Desc != null && tx.Desc.Length > 0) { encoded += JsonConvert.SerializeObject(tx.Desc) + "\n"; } encoded += JsonConvert.SerializeObject(tx.Nonce, settings) + "\n"; encoded += JsonConvert.SerializeObject(tx.Timestamp) + "\n"; encoded += JsonConvert.SerializeObject(tx.Version) + "\n"; if (tx.TxInputsExt != null) { for (var i = 0; i < tx.TxInputsExt.Count; i++) { var input = tx.TxInputsExt[i]; encoded += JsonConvert.SerializeObject(input.Bucket) + "\n"; if (input.Key.Length > 0) { encoded += JsonConvert.SerializeObject(input.Key) + "\n"; } if (input.RefTxid.Length > 0) { encoded += JsonConvert.SerializeObject(input.RefTxid) + "\n"; } encoded += JsonConvert.SerializeObject(input.RefOffset) + "\n"; } } if (tx.TxOutputsExt != null) { foreach (var output in tx.TxOutputsExt) { encoded += (JsonConvert.SerializeObject(output.Bucket) + "\n"); if (output.Key.Length > 0) { encoded += (JsonConvert.SerializeObject(output.Key) + "\n"); } if (output.Value.Length > 0) { encoded += (JsonConvert.SerializeObject(output.Value) + "\n"); } } } encoded += (JsonConvert.SerializeObject(tx.ContractRequests, settings) + "\n"); encoded += (JsonConvert.SerializeObject(tx.Initiator) + "\n"); encoded += (JsonConvert.SerializeObject(tx.AuthRequire) + "\n"); if (needSigns) { encoded += (JsonConvert.SerializeObject(tx.InitiatorSigns) + "\n"); encoded += (JsonConvert.SerializeObject(tx.AuthRequireSigns) + "\n"); } encoded += (JsonConvert.SerializeObject(tx.Coinbase) + "\n"); encoded += (JsonConvert.SerializeObject(tx.Autogen) + "\n"); Console.WriteLine("Debug: digest=\n" + encoded); var encodedBytes = Encoding.ASCII.GetBytes(encoded); return(XCrypto.DoubleSha256(encodedBytes)); }
private Transaction AssembleTx(Pb.UtxoOutput utxo, XCAccount account, List <string> authRequire, string to, BigInteger amount, Pb.InvokeResponse contractInvoke, string desc) { var tx = new Transaction(); // check param if (amount < 0 || account == null) { return(null); } // if have utxo, assemble utxo input/ouput if (utxo != null) { // assemble TxInputs tx.TxInputs = new List <TxInput>(); var total = BigInteger.Parse(utxo.TotalSelected); for (var i = 0; i < utxo.UtxoList.Count; i++) { var utxoItem = utxo.UtxoList[i]; var input = new TxInput { FromAddr = utxoItem.ToAddr.ToByteArray(), Amount = utxoItem.Amount.ToByteArray(), RefTxid = utxoItem.RefTxid.ToByteArray(), RefOffset = utxoItem.RefOffset, }; tx.TxInputs.Add(input); } tx.TxOutputs = new List <TxOutput>(); // Assemble utxo Output for transferring to if (amount > 0 && to != "") { // utxo check if (amount > total) { Console.WriteLine("Utxo use greater than utxo selected" + ", selected=" + total + ", use=", amount); return(null); } var output = new TxOutput() { ToAddr = Encoding.ASCII.GetBytes(to), Amount = amount.ToByteArray(), }; Array.Reverse(output.Amount, 0, output.Amount.Length); tx.TxOutputs.Add(output); total -= amount; } // Assemble contract fee if (contractInvoke != null && contractInvoke.GasUsed > 0) { var gasUsed = new BigInteger(contractInvoke.GasUsed); if (gasUsed > total) { Console.WriteLine("Utxo use greater than utxo selected" + ", selected=" + total + ", use=", gasUsed); return(null); } var output = new TxOutput() { ToAddr = Encoding.ASCII.GetBytes("$"), Amount = gasUsed.ToByteArray(), }; Array.Reverse(output.Amount, 0, output.Amount.Length); tx.TxOutputs.Add(output); total -= gasUsed; } // charge utxo to user if (total > 0) { var chargeOutput = new TxOutput() { ToAddr = Encoding.ASCII.GetBytes(account.Address), Amount = total.ToByteArray(), }; Array.Reverse(chargeOutput.Amount, 0, chargeOutput.Amount.Length); tx.TxOutputs.Add(chargeOutput); } } // Assemble contracts if (contractInvoke != null) { if (contractInvoke.Inputs.Count > 0) { tx.TxInputsExt = new List <TxInputExt>(); } if (contractInvoke.Outputs.Count > 0) { tx.TxOutputsExt = new List <TxOutputExt>(); } if (contractInvoke.Requests.Count > 0) { tx.ContractRequests = new List <InvokeRequest>(); } // TODO: transfer within contract is not supported foreach (var input in contractInvoke.Inputs) { var inputExt = new TxInputExt { Bucket = input.Bucket, Key = input.Key.ToByteArray(), RefTxid = input.RefTxid.ToByteArray(), RefOffset = input.RefOffset, }; tx.TxInputsExt.Add(inputExt); } foreach (var output in contractInvoke.Outputs) { var outputExt = new TxOutputExt { Bucket = output.Bucket, Key = output.Key.ToByteArray(), Value = output.Value.ToByteArray(), }; tx.TxOutputsExt.Add(outputExt); } foreach (var request in contractInvoke.Requests) { var invoke = new InvokeRequest { ModuleName = request.ModuleName, ContractName = request.ContractName, MethodName = request.MethodName, }; foreach (var arg in request.Args) { invoke.Args.Add(arg.Key, arg.Value.ToByteArray()); } foreach (var limit in request.ResourceLimits) { invoke.ResourceLimits.Add(new ResourceLimit { Type = (ResourceType)limit.Type, Limit = limit.Limit, }); } tx.ContractRequests.Add(invoke); } } // Assemble other data tx.Desc = Encoding.ASCII.GetBytes(desc); tx.Version = 1; tx.Coinbase = false; tx.Autogen = false; tx.Initiator = account.Address; if (authRequire != null && authRequire.Count > 0) { tx.AuthRequire = authRequire; } var digestHash = XDigest.MakeDigestHash(tx); var sign = XCrypto.SignHash(account.PrivateKey, digestHash); var signInfo = new SignatureInfo() { PublicKey = account.PublicKey.RawKey, Sign = sign, }; tx.InitiatorSigns = new List <SignatureInfo>(); tx.InitiatorSigns.Add(signInfo); if (authRequire != null && authRequire.Count > 0) { tx.AuthRequireSigns = new List <SignatureInfo>(); tx.AuthRequireSigns.Add(signInfo); } var txid = XDigest.MakeTransactionID(tx); tx.Txid = txid; return(tx); }
static void Main(string[] args) { var client = new XChainClient(); if (!client.Init("./data/keys", "127.0.0.1:37101")) { Console.WriteLine("Create client failed"); return; } // test asn1 BigInteger r = new BigInteger(190); BigInteger s = new BigInteger(1024567); var result = XCrypto.Asn1EncodeSign(r, s); Console.WriteLine("Encode result=" + XConvert.ByteArrayToHexString(result)); // test sign var data = Encoding.ASCII.GetBytes("123abc"); var sign = XCrypto.SignHash(client.Account.PrivateKey, data); Console.WriteLine("Sign result=" + XConvert.ByteArrayToHexString(sign)); // test verify sign var sign2 = XConvert.HexStringToByteArray("30450221008fb23b0a4e0c1b23cb11517fe25e2eb9ab92c57f62d0d2acf1485a2498ae5dfa02202f480e71c36784af24ca1af1aade44c689fd7a7805a3963e345de3fce71c6b96"); var valid = XCrypto.VerifySign(client.Account.PublicKey, sign2, data); Console.WriteLine("Verify result=" + valid); // test get balance var balance = client.GetBalance("xuper"); Console.WriteLine("Account balance=" + balance.ToString()); // hash test var tx = new Transaction(); tx.Desc = Encoding.ASCII.GetBytes("this is a desc"); tx.TxInputs = new List <TxInput>() { new TxInput { Amount = Encoding.ASCII.GetBytes("888"), FromAddr = Encoding.ASCII.GetBytes("dpzuVdosQrF2kmzumhVeFQZa1aYcdgFpN"), RefTxid = XConvert.HexStringToByteArray("3027697986fb8f926dc272697e5bc03b8286ef1d1e6604c85b043661b5a8b750"), RefOffset = 0, FrozenHeight = 0, } }; tx.TxOutputs = new List <TxOutput>() { new TxOutput { Amount = Encoding.ASCII.GetBytes("888"), ToAddr = Encoding.ASCII.GetBytes("alice"), } }; var digest = XDigest.MakeDigestHash(tx); Console.WriteLine("Digest hash=" + BitConverter.ToString(digest).Replace("-", "")); // make transaction var transRes = client.Transfer("xuper", "alice", new BigInteger(100), "test"); if (transRes.Error.ErrorCode != Errors.Success) { Console.WriteLine("Transfer failed, err=" + transRes.Error.ErrorMessage); } else { Console.WriteLine("Transfer success, txid=" + transRes.Txid); } // query transaction var txRes = client.QueryTx("xuper", transRes.Txid); if (txRes == null || txRes.Error.ErrorCode != Errors.Success) { Console.WriteLine("query tx failed"); } else { var txData = (Transaction)txRes.Data; Console.WriteLine("-------------- Transaction Info: -------------"); Console.WriteLine("Txid: " + transRes.Txid); if (tx.Blockid != null) { Console.WriteLine("Blockid: " + XConvert.ByteArrayToHexString(txData.Blockid)); } if (tx.Desc != null) { Console.WriteLine("Desc: " + Encoding.ASCII.GetString(tx.Desc)); } } //test new account var newAccountRes = client.NewContractAccount("xuper", "1111111111111111"); if (newAccountRes == null || newAccountRes.Error.ErrorCode != Errors.Success) { Console.WriteLine("New account failed"); } else { Console.WriteLine("New account success, account=" + (string)newAccountRes.Data); } //test deploy account var initArgs = new Dictionary <string, byte[]>(); initArgs["creator"] = Encoding.ASCII.GetBytes("xchain"); var deployRes = client.DeployWASMContract("xuper", "counter", "/Users/wangyucao/code/yucaowang/xuperunion/output/counter.wasm", "XC1111111111111111@xuper", initArgs, "c"); if (deployRes == null || deployRes.Error.ErrorCode != Errors.Success) { Console.WriteLine("Deploy Contract Failed"); } // test invoke contract var cArgs = new SortedDictionary <string, byte[]>(); cArgs.Add("key", Encoding.ASCII.GetBytes("xchain")); var invokeRes = client.InvokeContract("xuper", "counter", "increase", cArgs); if (invokeRes == null || invokeRes.Error.ErrorCode != Errors.Success) { Console.WriteLine("Invoke Contract Failed"); } else { Console.WriteLine("Contract Response:" + JsonConvert.SerializeObject(invokeRes.Data)); } }