After some further investigation, we realized that we have a race condition around ProtonLinkCreditState. Making an exclusive access to the receiver, and guarding some operations on it with state checks, has given us a stable solution so far.
Meanwhile, it might be great if pause/resume would be implemented in ProtonJ itself. Another request: implement event-driven hook in the ClientReceiver instead of in-memory blocking queue. Or provide another contract like ClientConsumer to do so. But that's another story. Thank you for your help! On Tue, Apr 7, 2026 at 1:43 PM Artem Bilan <[email protected]> wrote: > I think I have figured it out. > After gathering RabbitMQ logs I got this clue: > > 2026-04-07 16:59:02.368622+00:00 [info] <0.821.0> Connection from AMQP 1.0 > container 'ID:7629abd0-e49d-4c5a-826f-7dbc19e0a9d4:2:1': user 'guest' > authenticated using SASL mechanism ANONYMOUS and granted access to vhost '/' > 2026-04-07 16:59:02.390733+00:00 [warning] <0.827.0> Received Flow frame > for unknown link handle: {'v1_0.flow', > 2026-04-07 16:59:02.390733+00:00 [warning] <0.827.0> {uint,1}, > 2026-04-07 16:59:02.390733+00:00 [warning] <0.827.0> {uint,1600}, > 2026-04-07 16:59:02.390733+00:00 [warning] <0.827.0> {uint,1}, > 2026-04-07 16:59:02.390733+00:00 [warning] <0.827.0> {uint,2147483647}, > 2026-04-07 16:59:02.390733+00:00 [warning] <0.827.0> {uint,1}, > 2026-04-07 16:59:02.390733+00:00 [warning] <0.827.0> {uint,0}, > 2026-04-07 16:59:02.390733+00:00 [warning] <0.827.0> {uint,0}, > 2026-04-07 16:59:02.390733+00:00 [warning] <0.827.0> > undefined,false,undefined, > 2026-04-07 16:59:02.390733+00:00 [warning] <0.827.0> undefined} > 2026-04-07 16:59:02.390983+00:00 [warning] <0.827.0> Closing session for > connection <0.821.0>: {'v1_0.error', > 2026-04-07 16:59:02.390983+00:00 [warning] <0.827.0> {symbol, > 2026-04-07 16:59:02.390983+00:00 [warning] <0.827.0> > <<"amqp:session:unattached-handle">>}, > 2026-04-07 16:59:02.390983+00:00 [warning] <0.827.0> {utf8, > 2026-04-07 16:59:02.390983+00:00 [warning] <0.827.0> <<"Unattached link > handle: 1">>}, > 2026-04-07 16:59:02.390983+00:00 [warning] <0.827.0> undefined} > So, looks like we are trying to interact with a link which is not fully > ready on the broker side. > > Therefore I went forward and implemented reaction to this API: > > /** > * @return a {@link Future} that will be completed when the remote opens this > {@link Link}. > */ > Future<T> openFuture(); > > Something like this, for example: > > senderToReturn = > this.connectionFactory > .getConnection() > .openAnonymousSender(this.senderOptions); > Future<Sender> openFuture = senderToReturn.openFuture(); > this.sender = ProtonUtils.toSupplier(openFuture, > this.senderOptions.openTimeout()).get(); > > So far my tests are OK. > > I think this ticket can be closed. > > Thank you for your support! > > > > > On Tue, Mar 31, 2026 at 2:03 PM Artem Bilan <[email protected]> > wrote: > >> I'm still investigating the cause of premature and sproradic session >> closure in my tests. >> However I want to point that RabbitMQ does support several links per >> session. >> My original impression was wrong. >> Either way need to figure out how to pull RabbitMQ logs from >> Testcontainers when that test fails. >> >> On Mon, Mar 30, 2026 at 2:36 PM Timothy Bish <[email protected]> wrote: >> >>> I don't really know anything about the RabbitMQ implementation so I >>> cannot really provide any insights into why it closed the session but I >>> would guess that is the cause of your failed test, it might be sporadic due >>> to this being something that happens after your test is done or in the >>> process of closing down so it only gets seems sometimes. >>> >>> This is where your session was closed by the remote so I'd suggest >>> looking into why you might get the specific error and session closure. >>> <- AMQP:[310426339:0] >>> End{error=Error{condition=amqp:session:unattached-handle, >>> description='Unattached link handle: 2', info=null}} >>> -> AMQP:[310426339:0] End{error=null} >>> >>> The protonj2 client allows you to manage sessions as you like so if >>> Rabbit needs a session per producer or consumer that is definitely >>> something you can do, if you are using the connection level APIs to create >>> them you would already be using a single session for the entirety of the >>> connection's resources. >>> >>> On Mon, Mar 30, 2026 at 1:05 PM Artem Bilan via users < >>> [email protected]> wrote: >>> >>>> Hi Tim! >>>> Thank you for the tip! >>>> I added that tracing for frames, however it does not say me too much. >>>> Just test sporadically fails like with this trace: >>>> >>>> -> SASL:[310426339:0] AMQP,3,1,0,0 >>>> <- SASL:[310426339:0] AMQP,3,1,0,0 >>>> <- SASL:[310426339:0] SaslMechanisms{saslServerMechanisms=[PLAIN, >>>> AMQPLAIN, ANONYMOUS]} >>>> 2026-03-28 05:35:21,659 WARN >>>> org.apache.qpid.protonj2.engine.sasl.client.SaslMechanismSelector >>>> [ClientConnection :(ID:a54be302-d329-4598-8bfc-55b1cfed2e33:1:1): I/O >>>> Thread] : Caught exception while trying to create SASL mechanism AMQPLAIN: >>>> No Matching SASL Mechanism with name: AMQPLAIN >>>> -> SASL:[310426339:0] SaslInit{mechanism=ANONYMOUS, initialResponse="", >>>> hostname='localhost'} >>>> <- SASL:[310426339:0] SaslOutcome{code=OK, additionalData=null} >>>> -> AMQP:[310426339:0] AMQP,0,1,0,0 >>>> <- AMQP:[310426339:0] AMQP,0,1,0,0 >>>> -> AMQP:[310426339:0] Open{ >>>> containerId='ID:a54be302-d329-4598-8bfc-55b1cfed2e33:1:1', >>>> hostname='localhost', maxFrameSize=65536, channelMax=65535, >>>> idleTimeOut=30000, outgoingLocales=null, incomingLocales=null, >>>> offeredCapabilities=null, desiredCapabilities=[ANONYMOUS-RELAY], >>>> properties=null} >>>> -> AMQP:[310426339:0] Begin{remoteChannel=null, nextOutgoingId=0, >>>> incomingWindow=1600, outgoingWindow=2147483647, handleMax=null, >>>> offeredCapabilities=null, desiredCapabilities=null, properties=null} >>>> -> AMQP:[310426339:0] >>>> Attach{name='receiver-ID:a54be302-d329-4598-8bfc-55b1cfed2e33:1:1:1:1', >>>> handle=0, role=RECEIVER, sndSettleMode=UNSETTLED, rcvSettleMode=FIRST, >>>> source=Source{address='/queues/enable_amqp_queue1', durable=NONE, >>>> expiryPolicy=LINK_DETACH, timeout=0, dynamic=false, >>>> dynamicNodeProperties=null, distributionMode=null, filter=null, >>>> defaultOutcome=Modified{deliveryFailed=true, undeliverableHere=false, >>>> messageAnnotations=null}, outcomes=[amqp:accepted:list, amqp:rejected:list, >>>> amqp:released:list, amqp:modified:list], capabilities=null}, >>>> target=Target{address='/queues/enable_amqp_queue1', durable=NONE, >>>> expiryPolicy=SESSION_END, timeout=0, dynamic=false, >>>> dynamicNodeProperties=null, capabilities=null}, unsettled=null, >>>> incompleteUnsettled=null, initialDeliveryCount=null, maxMessageSize=null, >>>> offeredCapabilities=null, desiredCapabilities=null, properties=null} >>>> -> AMQP:[310426339:0] Flow{nextIncomingId=null, incomingWindow=1600, >>>> nextOutgoingId=0, outgoingWindow=2147483647, handle=0, deliveryCount=null, >>>> linkCredit=55, available=null, drain=false, echo=null, properties=null} >>>> -> AMQP:[310426339:0] >>>> Attach{name='receiver-ID:a54be302-d329-4598-8bfc-55b1cfed2e33:1:1:1:2', >>>> handle=1, role=RECEIVER, sndSettleMode=UNSETTLED, rcvSettleMode=FIRST, >>>> source=Source{address='/queues/enable_amqp_queue1', durable=NONE, >>>> expiryPolicy=LINK_DETACH, timeout=0, dynamic=false, >>>> dynamicNodeProperties=null, distributionMode=null, filter=null, >>>> defaultOutcome=Modified{deliveryFailed=true, undeliverableHere=false, >>>> messageAnnotations=null}, outcomes=[amqp:accepted:list, amqp:rejected:list, >>>> amqp:released:list, amqp:modified:list], capabilities=null}, >>>> target=Target{address='/queues/enable_amqp_queue1', durable=NONE, >>>> expiryPolicy=SESSION_END, timeout=0, dynamic=false, >>>> dynamicNodeProperties=null, capabilities=null}, unsettled=null, >>>> incompleteUnsettled=null, initialDeliveryCount=null, maxMessageSize=null, >>>> offeredCapabilities=null, desiredCapabilities=null, properties=null} >>>> -> AMQP:[310426339:0] Flow{nextIncomingId=null, incomingWindow=1600, >>>> nextOutgoingId=0, outgoingWindow=2147483647, handle=1, deliveryCount=null, >>>> linkCredit=55, available=null, drain=false, echo=null, properties=null} >>>> -> AMQP:[310426339:0] >>>> Attach{name='receiver-ID:a54be302-d329-4598-8bfc-55b1cfed2e33:1:1:1:3', >>>> handle=2, role=RECEIVER, sndSettleMode=UNSETTLED, rcvSettleMode=FIRST, >>>> source=Source{address='/queues/enable_amqp_queue1', durable=NONE, >>>> expiryPolicy=LINK_DETACH, timeout=0, dynamic=false, >>>> dynamicNodeProperties=null, distributionMode=null, filter=null, >>>> defaultOutcome=Modified{deliveryFailed=true, undeliverableHere=false, >>>> messageAnnotations=null}, outcomes=[amqp:accepted:list, amqp:rejected:list, >>>> amqp:released:list, amqp:modified:list], capabilities=null}, >>>> target=Target{address='/queues/enable_amqp_queue1', durable=NONE, >>>> expiryPolicy=SESSION_END, timeout=0, dynamic=false, >>>> dynamicNodeProperties=null, capabilities=null}, unsettled=null, >>>> incompleteUnsettled=null, initialDeliveryCount=null, maxMessageSize=null, >>>> offeredCapabilities=null, desiredCapabilities=null, properties=null} >>>> -> AMQP:[310426339:0] Flow{nextIncomingId=null, incomingWindow=1600, >>>> nextOutgoingId=0, outgoingWindow=2147483647, handle=2, deliveryCount=null, >>>> linkCredit=55, available=null, drain=false, echo=null, properties=null} >>>> <- AMQP:[310426339:0] Open{ containerId='rabbit@69e87c0daa99', >>>> hostname='null', maxFrameSize=131072, channelMax=63, idleTimeOut=30000, >>>> outgoingLocales=null, incomingLocales=null, >>>> offeredCapabilities=[LINK_PAIR_V1_0, ANONYMOUS-RELAY], >>>> desiredCapabilities=null, properties={node=rabbit@69e87c0daa99, >>>> cluster_name=rabbit@69e87c0daa99, copyright=Copyright (c) 2007-2026 >>>> Broadcom Inc and/or its subsidiaries, information=Licensed under the MPL >>>> 2.0. Website: https://rabbitmq.com, platform=Erlang/OTP 27.3.4.9, >>>> product=RabbitMQ, version=4.2.5}} >>>> <- AMQP:[310426339:0] Begin{remoteChannel=0, nextOutgoingId=0, >>>> incomingWindow=400, outgoingWindow=4294967295, handleMax=255, >>>> offeredCapabilities=null, desiredCapabilities=null, properties=null} >>>> -> AMQP:[310426339:0] >>>> Attach{name='sender-ID:a54be302-d329-4598-8bfc-55b1cfed2e33:1:1:1:1', >>>> handle=3, role=SENDER, sndSettleMode=UNSETTLED, rcvSettleMode=FIRST, >>>> source=Source{address='null', durable=NONE, expiryPolicy=LINK_DETACH, >>>> timeout=0, dynamic=false, dynamicNodeProperties=null, >>>> distributionMode=null, filter=null, defaultOutcome=null, >>>> outcomes=[amqp:accepted:list, amqp:rejected:list, amqp:released:list, >>>> amqp:modified:list], capabilities=null}, target=Target{address='null', >>>> durable=NONE, expiryPolicy=SESSION_END, timeout=0, dynamic=false, >>>> dynamicNodeProperties=null, capabilities=null}, unsettled=null, >>>> incompleteUnsettled=null, initialDeliveryCount=0, maxMessageSize=null, >>>> offeredCapabilities=null, desiredCapabilities=null, properties=null} >>>> <- AMQP:[310426339:0] >>>> Attach{name='receiver-ID:a54be302-d329-4598-8bfc-55b1cfed2e33:1:1:1:1', >>>> handle=0, role=SENDER, sndSettleMode=UNSETTLED, rcvSettleMode=FIRST, >>>> source=Source{address='/queues/enable_amqp_queue1', durable=NONE, >>>> expiryPolicy=LINK_DETACH, timeout=0, dynamic=false, >>>> dynamicNodeProperties=null, distributionMode=null, filter=null, >>>> defaultOutcome=Released{}, outcomes=[amqp:accepted:list, >>>> amqp:rejected:list, amqp:released:list, amqp:modified:list], >>>> capabilities=null}, target=null, unsettled=null, incompleteUnsettled=null, >>>> initialDeliveryCount=0, maxMessageSize=null, offeredCapabilities=null, >>>> desiredCapabilities=null, properties=null} >>>> <- AMQP:[310426339:0] >>>> Attach{name='receiver-ID:a54be302-d329-4598-8bfc-55b1cfed2e33:1:1:1:2', >>>> handle=1, role=SENDER, sndSettleMode=UNSETTLED, rcvSettleMode=FIRST, >>>> source=Source{address='/queues/enable_amqp_queue1', durable=NONE, >>>> expiryPolicy=LINK_DETACH, timeout=0, dynamic=false, >>>> dynamicNodeProperties=null, distributionMode=null, filter=null, >>>> defaultOutcome=Released{}, outcomes=[amqp:accepted:list, >>>> amqp:rejected:list, amqp:released:list, amqp:modified:list], >>>> capabilities=null}, target=null, unsettled=null, incompleteUnsettled=null, >>>> initialDeliveryCount=0, maxMessageSize=null, offeredCapabilities=null, >>>> desiredCapabilities=null, properties=null} >>>> <- AMQP:[310426339:0] >>>> Attach{name='receiver-ID:a54be302-d329-4598-8bfc-55b1cfed2e33:1:1:1:3', >>>> handle=2, role=SENDER, sndSettleMode=UNSETTLED, rcvSettleMode=FIRST, >>>> source=Source{address='/queues/enable_amqp_queue1', durable=NONE, >>>> expiryPolicy=LINK_DETACH, timeout=0, dynamic=false, >>>> dynamicNodeProperties=null, distributionMode=null, filter=null, >>>> defaultOutcome=Released{}, outcomes=[amqp:accepted:list, >>>> amqp:rejected:list, amqp:released:list, amqp:modified:list], >>>> capabilities=null}, target=null, unsettled=null, incompleteUnsettled=null, >>>> initialDeliveryCount=0, maxMessageSize=null, offeredCapabilities=null, >>>> desiredCapabilities=null, properties=null} >>>> <- AMQP:[310426339:0] >>>> Attach{name='sender-ID:a54be302-d329-4598-8bfc-55b1cfed2e33:1:1:1:1', >>>> handle=3, role=RECEIVER, sndSettleMode=UNSETTLED, rcvSettleMode=FIRST, >>>> source=Source{address='null', durable=NONE, expiryPolicy=LINK_DETACH, >>>> timeout=0, dynamic=false, dynamicNodeProperties=null, >>>> distributionMode=null, filter=null, defaultOutcome=null, >>>> outcomes=[amqp:accepted:list, amqp:rejected:list, amqp:released:list, >>>> amqp:modified:list], capabilities=null}, target=Target{address='null', >>>> durable=NONE, expiryPolicy=SESSION_END, timeout=0, dynamic=false, >>>> dynamicNodeProperties=null, capabilities=null}, unsettled=null, >>>> incompleteUnsettled=null, initialDeliveryCount=null, >>>> maxMessageSize=16777216, offeredCapabilities=null, >>>> desiredCapabilities=null, properties=null} >>>> <- AMQP:[310426339:0] Flow{nextIncomingId=0, incomingWindow=400, >>>> nextOutgoingId=0, outgoingWindow=4294967295, handle=3, deliveryCount=0, >>>> linkCredit=170, available=null, drain=null, echo=null, properties=null} >>>> -> AMQP:[310426339:0] Transfer{handle=3, deliveryId=0, deliveryTag={0}, >>>> messageFormat=0, settled=false, more=false, rcvSettleMode=null, state=null, >>>> resume=null, aborted=null, batchable=null} - >>>> "\x00Sp\xc0\x04\x02AP\x00\x00Ss\xd0\x00\x00\x00B\x00\x00\x00\x0a@ >>>> "...(truncated) >>>> <- AMQP:[310426339:0] Transfer{handle=0, deliveryId=0, >>>> deliveryTag=DeliveryTag: {[0, 0, 0, 0]}, messageFormat=0, settled=false, >>>> more=false, rcvSettleMode=null, state=null, resume=null, aborted=null, >>>> batchable=null} - "\x00Sp\xc0\x07\x05AP\x00@AC >>>> \x00Sr\xc12\x04\xa3\x0ax-exchange\xa1"...(truncated) >>>> <- AMQP:[310426339:0] Disposition{role=RECEIVER, first=0, last=0, >>>> settled=true, state=Accepted{}, batchable=false} >>>> -> AMQP:[310426339:0] Flow{nextIncomingId=1, incomingWindow=1600, >>>> nextOutgoingId=1, outgoingWindow=2147483647, handle=0, deliveryCount=1, >>>> linkCredit=0, available=null, drain=false, echo=null, properties=null} >>>> -> AMQP:[310426339:0] Detach{handle=0, closed=true, error=null} >>>> -> AMQP:[310426339:0] Flow{nextIncomingId=1, incomingWindow=1600, >>>> nextOutgoingId=1, outgoingWindow=2147483647, handle=1, deliveryCount=0, >>>> linkCredit=0, available=null, drain=false, echo=null, properties=null} >>>> <- AMQP:[310426339:0] Detach{handle=0, closed=true, error=null} >>>> -> AMQP:[310426339:0] Flow{nextIncomingId=1, incomingWindow=1600, >>>> nextOutgoingId=1, outgoingWindow=2147483647, handle=2, deliveryCount=0, >>>> linkCredit=0, available=null, drain=false, echo=null, properties=null} >>>> <- AMQP:[310426339:0] Transfer{handle=1, deliveryId=1, >>>> deliveryTag=DeliveryTag: {[0, 0, 0, 0]}, messageFormat=0, settled=false, >>>> more=false, rcvSettleMode=null, state=null, resume=null, aborted=null, >>>> batchable=null} - "\x00Sp\xc0\x07\x05AP\x00@BC >>>> \x00Sr\xc12\x04\xa3\x0ax-exchange\xa1"...(truncated) >>>> -> AMQP:[310426339:0] Detach{handle=2, closed=true, error=null} >>>> <- AMQP:[310426339:0] Detach{handle=2, closed=true, error=null} >>>> -> AMQP:[310426339:0] Detach{handle=1, closed=true, error=null} >>>> <- AMQP:[310426339:0] >>>> End{error=Error{condition=amqp:session:unattached-handle, >>>> description='Unattached link handle: 2', info=null}} >>>> -> AMQP:[310426339:0] End{error=null} >>>> I don't know if that is the case, but might be that RabbitMQ requires >>>> explicit session management for consumer and/or producers. >>>> At the same time I saw somewhere that some AMQP brokers requires one >>>> session per connection... >>>> I might consider to add a session management into my components if that >>>> is the case. >>>> >>>> Any thoughts? >>>> >>>> Thank you very much! >>>> >>>> On 2026/03/26 14:40:32 Timothy Bish wrote: >>>> > On 3/25/26 11:59, Artem Bilan via users wrote: >>>> > > Hi there! >>>> > > >>>> > > I am developing Spring Framework client based on the QPid ProtonJ 2 >>>> > > Client: >>>> > > >>>> https://github.com/spring-projects/spring-amqp/tree/main/spring-amqp-client/src >>>> . >>>> > > >>>> > > One of my tests is sporadically failing like: >>>> > >>>> > Without an AMQP frame trace it is not possible to say why this is >>>> > failing, it is valid for the error to occur if the session is >>>> remotely >>>> > closed. The configuration guide in the docs explains how to enable >>>> frame >>>> > tracing, with that enabled you can see the frames that arrived around >>>> > the time this error occurs. >>>> > >>>> > >>>> https://github.com/apache/qpid-protonj2/blob/main/protonj2-client-docs/Configuration.md#logging >>>> > >>>> > >>>> > > >>>> > > Caused by: java.lang.IllegalStateException: Cannot create new >>>> Receiver >>>> > > from closed Session >>>> > > >>>> > > >>>> > > at >>>> > > >>>> org.apache.qpid.protonj2.engine.impl.ProtonSession.checkSessionClosed(ProtonSession.java:670) >>>> >>>> > > >>>> > > >>>> > > at >>>> > > >>>> org.apache.qpid.protonj2.engine.impl.ProtonSession.receiver(ProtonSession.java:396) >>>> >>>> > > >>>> > > >>>> > > at >>>> > > >>>> org.apache.qpid.protonj2.engine.impl.ProtonSession.receiver(ProtonSession.java:59) >>>> >>>> > > >>>> > > >>>> > > at >>>> > > >>>> org.apache.qpid.protonj2.client.impl.ClientReceiverBuilder.createReceiver(ClientReceiverBuilder.java:142) >>>> >>>> > > >>>> > > >>>> > > at >>>> > > >>>> org.apache.qpid.protonj2.client.impl.ClientReceiverBuilder.receiver(ClientReceiverBuilder.java:61) >>>> >>>> > > >>>> > > >>>> > > at >>>> > > >>>> org.apache.qpid.protonj2.client.impl.ClientSession.internalOpenReceiver(ClientSession.java:391) >>>> >>>> > > >>>> > > >>>> > > at >>>> > > >>>> org.apache.qpid.protonj2.client.impl.ClientConnection.lambda$openReceiver$3(ClientConnection.java:279) >>>> >>>> > > >>>> > > >>>> > > at >>>> > > >>>> io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:148) >>>> >>>> > > >>>> > > >>>> > > at >>>> > > >>>> io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:141) >>>> >>>> > > >>>> > > >>>> > > at >>>> > > >>>> io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:535) >>>> >>>> > > >>>> > > >>>> > > at >>>> io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:405) >>>> > > >>>> > > at >>>> > > >>>> io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1195) >>>> >>>> > > >>>> > > >>>> > > at >>>> > > >>>> io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) >>>> > > >>>> > > >>>> > > I have a single connection object per test suite lifecycle. >>>> > > The code I try to create a Receiver is like: >>>> > > ClientReceiver receiver = >>>> > > >>>> (ClientReceiver)connection.openReceiver(queue,receiverOptions) >>>> > > .addCredit(this.initialCredits); >>>> > > Which apparently leads to the shared internal session in that >>>> connection. >>>> > > >>>> > > The broker I test against is RabbitMQ 4.2. >>>> > > >>>> > > So, the question is: if I'm doing something wrong or missing >>>> anything. >>>> > > I also do have a reconnectEnabled on the connection. >>>> > > >>>> > > Please, let me know if you need anything else. >>>> > > >>>> > > Thank you! >>>> > > >>>> > > Regards, >>>> > > Artem Bilan >>>> > >>>> > >>>> > -- >>>> > Tim Bish >>>> > >>>> >>> >>> >>> -- >>> -- >>> Tim Bish >>> >>>
smime.p7s
Description: S/MIME Cryptographic Signature
