/// <summary> /// Hash returns the network-specific transaction hash for a signed transaction. /// </summary> /// <param name="request"></param> /// <returns></returns> public JObject ConstructionHash(ConstructionHashRequest request) { NeoTransaction neoTx; try { neoTx = NeoTransaction.DeserializeFrom(request.SignedTransaction.HexToBytes()); } catch (Exception) { return(Error.TX_DESERIALIZE_ERROR.ToJson()); } var hash = neoTx.Hash.ToString(); ConstructionHashResponse response = new ConstructionHashResponse(hash); return(response.ToJson()); }
/// <summary> /// Submit a pre-signed transaction to the node. This call should not block on the transaction being included in a block. /// Rather, it should return immediately with an indication of whether or not the transaction was included in the mempool. /// The transaction submission response should only return a 200 status if the submitted transaction could be included in the mempool. /// Otherwise, it should return an error. /// </summary> /// <param name="request"></param> /// <returns></returns> public JObject ConstructionSubmit(ConstructionSubmitRequest request) { NeoTransaction neoTx; try { neoTx = NeoTransaction.DeserializeFrom(request.SignedTransaction.HexToBytes()); } catch (Exception) { return(Error.TX_DESERIALIZE_ERROR.ToJson()); } RelayResultReason reason = system.Blockchain.Ask <RelayResultReason>(neoTx).Result; switch (reason) { case RelayResultReason.Succeed: TransactionIdentifier transactionIdentifier = new TransactionIdentifier(neoTx.Hash.ToString()); ConstructionSubmitResponse response = new ConstructionSubmitResponse(transactionIdentifier); return(response.ToJson()); case RelayResultReason.AlreadyExists: return(Error.ALREADY_EXISTS.ToJson()); case RelayResultReason.OutOfMemory: return(Error.OUT_OF_MEMORY.ToJson()); case RelayResultReason.UnableToVerify: return(Error.UNABLE_TO_VERIFY.ToJson()); case RelayResultReason.Invalid: return(Error.TX_INVALID.ToJson()); case RelayResultReason.PolicyFail: return(Error.POLICY_FAIL.ToJson()); default: return(Error.UNKNOWN_ERROR.ToJson()); } }
public override void Deserialize(BinaryReader reader) { base.Deserialize(reader); Transactions = new Transaction[reader.ReadVarInt(MaxTransactionsPerBlock)]; if (Transactions.Length == 0) { throw new FormatException(); } HashSet <UInt256> hashes = new HashSet <UInt256>(); for (int i = 0; i < Transactions.Length; i++) { Transactions[i] = Transaction.DeserializeFrom(reader); if (i == 0) { if (Transactions[0].Type != TransactionType.MinerTransaction) { throw new FormatException(); } } else { if (Transactions[i].Type == TransactionType.MinerTransaction) { throw new FormatException(); } } if (!hashes.Add(Transactions[i].Hash)) { throw new FormatException(); } } if (MerkleTree.ComputeRoot(Transactions.Select(p => p.Hash).ToArray()) != MerkleRoot) { throw new FormatException(); } }
/// <summary> /// Parse is called on both unsigned and signed transactions to understand the intent of the formulated transaction. /// This is run as a sanity check before signing (after `/construction/payloads`) and before broadcast (after `/construction/combine`). /// </summary> /// <param name="request"></param> /// <returns></returns> public JObject ConstructionParse(ConstructionParseRequest request) { NeoTransaction neoTx; try { if (request.Signed) { neoTx = NeoTransaction.DeserializeFrom(request.Transaction.HexToBytes()); } else { byte[] rawTx = request.Transaction.HexToBytes(); TransactionType type = (TransactionType)rawTx[0]; switch (type) { case TransactionType.ClaimTransaction: neoTx = new ClaimTransaction(); break; case TransactionType.ContractTransaction: neoTx = new ContractTransaction(); break; case TransactionType.StateTransaction: neoTx = new StateTransaction(); break; case TransactionType.InvocationTransaction: neoTx = new InvocationTransaction(); break; default: throw new ArgumentException(); } using (MemoryStream ms = new MemoryStream(rawTx, false)) using (BinaryReader br = new BinaryReader(ms, Encoding.UTF8)) { (neoTx as IVerifiable).DeserializeUnsigned(br); } } } catch (Exception) { return(Error.TX_DESERIALIZE_ERROR.ToJson()); } Transaction tx = ConvertTx(neoTx); Operation[] operations = tx.Operations; string[] signers = new string[0]; if (request.Signed) { signers = GetSignersFromWitnesses(neoTx.Witnesses); if (signers is null) { return(Error.TX_WITNESS_INVALID.ToJson()); } } ConstructionParseResponse response = new ConstructionParseResponse(operations, signers, tx.Metadata); return(response.ToJson()); }