internal SubmitMessageReceipt FillProperties(TransactionID transactionId, SubmitMessageReceipt receipt) { FillCommonProperties(transactionId, receipt); receipt.RunningHash = TopicRunningHash?.ToByteArray(); receipt.RunningHashVersion = TopicRunningHashVersion; receipt.SequenceNumber = TopicSequenceNumber; return(receipt); }
protected async Task HandleValidSubmit() { _output = null; await _network.ExecuteAsync(_input.Gateway, _input.Payer, async client => { var message = _input.MessageIsHex ? Hex.ToBytes(_input.Message) : Encoding.UTF8.GetBytes(_input.Message); _output = await client.SubmitMessageAsync(_input.Topic, message, ctx => ctx.Memo = _input.Memo?.Trim()); }); }
/// <summary> /// Sends an HCS message of arbitrary size /// to the network by breaking the message /// into segments, submitting each segment /// in sequence. Manages the segment metadata /// internally, returning an array of receipts /// representing the transactions required to /// upload the entier message. /// </summary> /// <param name="client"> /// A Hashgraph Client instance. /// </param> /// <param name="topic"> /// The address of the topic for the message. /// </param> /// <param name="message"> /// The value of the message, may exceed the /// network limit size. /// </param> /// <param name="segmentSize"> /// The maximum size of each segment. Must /// be under the current allowed size for /// transactions currently supported by the /// network. The method will break the /// message into as many segments as necessary /// to fulfill uploading the entire message. /// </param> /// <param name="signatory"> /// The signatory containing any additional private keys or callbacks /// to meet the key signing requirements for participants. /// </param> /// <param name="configure"> /// Optional callback method providing an opportunity to modify /// the execution configuration for just this method call. /// It is executed prior to submitting the request to the network. /// </param> /// <returns> /// An array of Submit Message Receipts indicating success, one for each /// segment uploaded. The Transaction ID of the first receipt matches /// the correlation transaction ID for the series of message segments /// as a whole. /// </returns> /// <exception cref="ArgumentOutOfRangeException">If required arguments are missing.</exception> /// <exception cref="InvalidOperationException">If required context configuration is missing.</exception> /// <exception cref="PrecheckException">If the gateway node create rejected the request upon submission.</exception> /// <exception cref="ConsensusException">If the network was unable to come to consensus before the duration of the transaction expired.</exception> /// <exception cref="TransactionException">If the network rejected the create request as invalid or had missing data.</exception> public static async Task <SubmitMessageReceipt[]> SubmitLargeMessageAsync(this Client client, Address topic, ReadOnlyMemory <byte> message, int segmentSize, Signatory?signatory = null, Action <IContext>?configure = null) { await using var configuredClient = client.Clone(configure); var segmentCount = (message.Length - 1) / segmentSize + 1; var receipts = new SubmitMessageReceipt[segmentCount]; receipts[0] = await configuredClient.SubmitMessageAsync(new SubmitMessageParams { Topic = topic, Segment = segmentCount > 1 ? message.Slice(0, segmentSize) : message, Index = 1, TotalSegmentCount = segmentCount, Signatory = signatory }).ConfigureAwait(false); var parentTx = receipts[0].Id; for (int i = 1; i < segmentCount - 1; i++) { receipts[i] = await configuredClient.SubmitMessageAsync(new SubmitMessageParams { Topic = topic, Segment = message.Slice(segmentSize *i, segmentSize), ParentTxId = parentTx, Index = i + 1, TotalSegmentCount = segmentCount, Signatory = signatory }).ConfigureAwait(false); } if (segmentCount > 1) { receipts[segmentCount - 1] = await configuredClient.SubmitMessageAsync(new SubmitMessageParams { Topic = topic, Segment = message.Slice(segmentSize * (segmentCount - 1)), ParentTxId = parentTx, Index = segmentCount, TotalSegmentCount = segmentCount, Signatory = signatory }).ConfigureAwait(false); } return(receipts); }
public async Task CanSubmitTwoSegmentedMessage() { await using var fx = await TestTopic.CreateAsync(_network); var submitParams = new SubmitMessageParams[2]; var receipt = new SubmitMessageReceipt[2]; submitParams[0] = new SubmitMessageParams { Topic = fx.Record.Topic, Segment = Encoding.ASCII.GetBytes(Generator.String(120, 199)), Index = 1, TotalSegmentCount = 2, Signatory = fx.ParticipantPrivateKey }; receipt[0] = await fx.Client.SubmitMessageAsync(submitParams[0]); Assert.Equal(ResponseCode.Success, receipt[0].Status); Assert.Equal(1ul, receipt[0].SequenceNumber); Assert.False(receipt[0].RunningHash.IsEmpty); Assert.Equal(3ul, receipt[0].RunningHashVersion); var txId = receipt[0].Id; submitParams[1] = new SubmitMessageParams { Topic = fx.Record.Topic, Segment = Encoding.ASCII.GetBytes(Generator.String(120, 199)), ParentTxId = txId, Index = 2, TotalSegmentCount = 2, Signatory = fx.ParticipantPrivateKey }; receipt[1] = await fx.Client.SubmitMessageAsync(submitParams[1]); Assert.Equal(ResponseCode.Success, receipt[1].Status); Assert.Equal(2ul, receipt[1].SequenceNumber); Assert.False(receipt[1].RunningHash.IsEmpty); Assert.Equal(3ul, receipt[1].RunningHashVersion); var info = await fx.Client.GetTopicInfoAsync(fx.Record.Topic); Assert.Equal(fx.Memo, info.Memo); Assert.NotEmpty(info.RunningHash.ToArray()); Assert.Equal(2UL, info.SequenceNumber); Assert.True(info.Expiration > DateTime.MinValue); Assert.Equal(new Endorsement(fx.AdminPublicKey), info.Administrator); Assert.Equal(new Endorsement(fx.ParticipantPublicKey), info.Participant); Assert.True(info.AutoRenewPeriod > TimeSpan.MinValue); Assert.Equal(fx.TestAccount.Record.Address, info.RenewAccount); AssertHg.NotEmpty(info.Ledger); await Task.Delay(7000); // give the beta net time to sync try { await using var mirror = _network.NewMirror(); var topicMessages = await TopicMessageCapture.CaptureOrTimeoutAsync(mirror, fx.Record.Topic, submitParams.Length, 7000); if (topicMessages.Length == 0) { _network.Output?.WriteLine("INDETERMINATE TEST - MIRROR NODE DID NOT RETURN TOPIC IN ALLOWED TIME"); } else { Assert.Equal(2, topicMessages.Length); for (int i = 0; i < topicMessages.Length; i++) { var topicMessage = topicMessages[i]; Assert.Equal(fx.Record.Topic, topicMessage.Topic); Assert.Equal((ulong)i + 1, topicMessage.SequenceNumber); Assert.Equal(receipt[i].RunningHash.ToArray(), topicMessage.RunningHash.ToArray()); Assert.Equal(submitParams[i].Segment.ToArray(), topicMessage.Messsage.ToArray()); Assert.NotNull(topicMessage.SegmentInfo); Assert.Equal(txId, topicMessage.SegmentInfo.ParentTxId); Assert.Equal(i + 1, topicMessage.SegmentInfo.Index); Assert.Equal(submitParams.Length, topicMessage.SegmentInfo.TotalSegmentCount); } } } catch (MirrorException mex) when(mex.Code == MirrorExceptionCode.TopicNotFound) { _network.Output?.WriteLine("INDETERMINATE TEST - MIRROR NODE DID NOT RECEIVE TOPIC CREATE IN ALLOWED TIME"); return; } }