When I test the a Contract whose ContractState has a LinearPointer to another state, the log first shows the warning
[WARN] 15:13:20,131 [Test worker] transactions.TransactionBuilder. - WARNING: You must pass in a ServiceHub reference to TransactionBuilder to resolve state pointers outside of flows. If you are writing a unit test then pass in a MockServices instance.
and of course the test failed, because the LedgerTransaction verified by the Contract do not have the pointed-to state resolved.
So I followed the instruction and passed the MockService to the TransactionBuilder. But the following error occured:
java.lang.UnsupportedOperationException
at net.corda.testing.node.MockServices.getVaultService(MockServices.kt:438)
at net.corda.core.contracts.LinearPointer.resolve(StatePointer.kt:183)
at net.corda.core.transactions.TransactionBuilder.resolveStatePointers(TransactionBuilder.kt:738)
at net.corda.core.transactions.TransactionBuilder.addOutputState(TransactionBuilder.kt:804)
When I dug into the source code, I found that MockService's vaultService can not be retrieved:
override val vaultService: VaultService get() = throw UnsupportedOperationException()
So, how am I supposed to test this kind of Contract whose verification involves resolving states referenced by StatePointers?
Ok, a solution struck me when I am writing the question:
Mannually add the pointed-to state to the transaction as a reference state
Related
I am using C++/winRT UWP to discover and connect to Bluetooth Low Energy devices. I am using the advertisment watcher to look for advertisements from devices I can support. This works.
Then I pick one to connect to. The connection procedure is a little weird by my way of thinking but according to the microsoft docs one Calls this FromBluetoothAddressAsync() with the BluetoothAddress and two things happen; one gets the BluetoothLEDevice AND a connection attempt is made. One needs to register a handler for the connection status changed event BUT you can't do that until you get the BluetoothLEDevice.
Is there a timing issue causing the exception? Has the connection already happened BEFORE I get the BluetoothLEDevice object? Below is the code and below that is the log:
void BtleHandler::connectToDevice(BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
OutputDebugStringA("Connect to device called\n");
// My God this async stuff took me a while to figure out! See https://msdn.microsoft.com/en-us/magazine/mt846728.aspx
IAsyncOperation<Windows::Devices::Bluetooth::BluetoothLEDevice> async = // assuming the address type is how I am to behave ..
BluetoothLEDevice::FromBluetoothAddressAsync(eventArgs.BluetoothAddress(), BluetoothAddressType::Random);
bluetoothLEDevice = async.get();
OutputDebugStringA("BluetoothLEDevice returned\n");
bluetoothLEDevice.ConnectionStatusChanged({ this, &BtleHandler::onConnectionStatusChanged });
// This method not only gives you the device but it also initiates a connection
}
The above code generates the following log:
New advertisment/scanResponse with UUID 00001809-0000-1000-8000-00805F9B34FB
New ad/scanResponse with name Philips ear thermometer and UUID 00001809-0000-1000-8000-00805F9B34FB
Connect to device called
ERROR here--> onecoreuap\drivers\wdm\bluetooth\user\winrt\common\bluetoothutilities.cpp(509)\Windows.Devices.Bluetooth.dll!03BEFDD6: (caller: 03BFB977) ReturnHr(1) tid(144) 80070490 Element not found.
ERROR here--> onecoreuap\drivers\wdm\bluetooth\user\winrt\device\bluetoothledevice.cpp(428)\Windows.Devices.Bluetooth.dll!03BFB9B7: (caller: 03BFAF01) ReturnHr(2) tid(144) 80070490 Element not found.
BluetoothLEDevice returned
Exception thrown at 0x0F5CDF2F (WindowsBluetoothAdapter.dll) in BtleScannerTest.exe: 0xC0000005: Access violation reading location 0x00000000.
It sure looks like there is a timing issue. But if it is, I have no idea how to resolve it. I cannot register for the event if I don't have a BluetoothLEDevice object! I cannot figure out a way to get the BluetoothLEDevice object without invoking a connection.
================================ UPDATE =============================
Changed the methods to IAsyncAction and used co_await as suggested by #IInspectable. No difference. The problem is clearly that the registered handler is out of scope or something is wrong with it. I tried a get_strong() instead of a 'this' in the registration, but the compiler would not accept it (said identifier 'get_strong()' is undefined). However, if I commented out the registration, no exception is thrown but I still get these log messages
onecoreuap\drivers\wdm\bluetooth\user\winrt\common\bluetoothutilities.cpp(509)\Windows.Devices.Bluetooth.dll!0F27FDD6: (caller: 0F28B977) ReturnHr(3) tid(253c) 80070490 Element not found.
onecoreuap\drivers\wdm\bluetooth\user\winrt\device\bluetoothledevice.cpp(428)\Windows.Devices.Bluetooth.dll!0F28B9B7: (caller: 0F28AF01) ReturnHr(4) tid(253c) 80070490 Element not found.
But the program continues to run an I continue to discover and connect. But since I can't get the connection event it is kind of useless at this stage.
I hate my answer. But after asynching and co-routining everything under the sun, the problem is unsolvable by me:
This method
bluetoothLEDevice = co_await BluetoothLEDevice::FromBluetoothAddressAsync(eventArgs.BluetoothAddress(), BluetoothAddressType::Random);
returns NULL. That should not happen and there is not much I can do about it. I read that as a broken BLE API.
A BTLE Central should be able to do as follows
Discover a device if new then:
If user selects connect, connect to
the device
perform service discovery
read/write/enable
characteristics as needed
handle indications/notifications
If at any time the peripheral sends a security request or insufficient authentication error, start pairing
repeat the action that caused the insufficient authentication.
On disconnect, save the paired and bonded state if the device is pairable.
On rediscovery of the device, if unpaired (not a pairable device)
repeat above
If paired and bonded
start encryption
work with the device; no need to re-enable or do service discovery
========================= MORE INFO ===================================
This is what the log shows when the method is called
Connect to device called
onecoreuap\drivers\wdm\bluetooth\user\winrt\common\bluetoothutilities.cpp(509)\Windows.Devices.Bluetooth.dll!0496FDD6: (caller: 0497B977) ReturnHr(1) tid(3b1c) 80070490 Element not found.
onecoreuap\drivers\wdm\bluetooth\user\winrt\device\bluetoothledevice.cpp(428)\Windows.Devices.Bluetooth.dll!0497B9B7: (caller: 0497AF01) ReturnHr(2) tid(3b1c) 80070490 Element not found.
BluetoothLEDevice returned is NULL. Can't register
Since the BluetoothLEDevice is NULL, I do not attempt to register.
================= MORE INFO ===================
I should also add that taking an over-the-air sniff reveals that there is never a connection event. Though the method is supposed to initiate a connection as well as return the BluetoothLEDevice object, it ends up doing neither. My guess is that the method requires more pre-use setup of the system that only the DeviceWatcher does. The AdvertisementWatcher probably does not.
In BLE you always have to wait for every operation to complete.
I am not an expert in C++, but in C# the async connection procedure returns a bool if it was successful.
In C++ the IAsyncOperation does not have a return type, so there is no way to know if the connection procedure was successful or completed.
You will have to await the IAsyncOperation and make sure that you have a BluetoothLEDevice object, before you attach the event handler.
To await an IAsyncOperation there is a question/answer on how to await anIAsyncOperation:
How to wait for an IAsyncAction? How to wait for an IAsyncAction?
While upgrading from Corda 3 to Corda 4, I have an issue commiting a State to our node's ledger with only one Party. A single Party is able to create a state, notarize it, but CANNOT commit to the Corda 4 ledger without asking for an external third party.
The error Corda 4 produces (which Corda 3 did not produce) is the following:
(1) java.lang.IllegalArgumentException: A flow session for each external participant to the transaction must be provided. If you wish to continue using this insecure API then specify a target platform version of less than 4 for your CorDapp.
More specific context: Using FinalityFlow without a session yields a 'session required for external parties' error and does not complete. Adding only a session (e.g. session = initiateFlow(PartyA) ) results in an error that 'local nodes should not be included.'
Is there a workaround regarding this solution? It's important (for our use case) that a single Party can create a State and modify the State information without the involvement of other parties. Other use cases (where multiple parties are included) stem from this use case. Any guidance is greatly appreciated.
I think the error message is pretty spot on here. Just change the way you call FinalityFlow during your issuance such that it doesn’t contain a flow session to itself i.e.
return subFlow(new FinalityFlow(signedTransaction));
Although you may get a deprecation warning, in which case, do the following
return subFlow(FinalityFlow(stx, emptyList()))
When running a Corda flow, I receive the following error:
java.lang.IllegalStateException: No transaction in context
How can I solve this issue?
This issue is likely caused by a failure to annotate a function called from within a flow with the #Suspendable annotation. This could either be FlowLogic.call, or a function called from within FlowLogic.call (e.g. SignTransactionFlow.checkTransaction if you are overriding this function as part of a call to CollectSignaturesFlow).
If you run flow tests with the following command line flag:
-Dco.paralleluniverse.fibers.verifyInstrumentation=true
Then the missing annotation will be highlighted if it causes an error. However, this will slow down the running of the tests.
We have a use case which requires the following steps:
(1) Initiator triggers the transaction flow through UI
(2) The flow is initiated, signed by the initiator and sent to recipient for his verification and signatures (in Corda)
(3) The initiator's flow should get suspended until the recipient validates the transaction by verifying the contract code and submits "verified" again through the UI
(4) This should restart the initiator's flow and the remaining process should be followed as expected in Corda
It was mentioned a few weeks back that user interaction is not yet supported in Corda; is this feature still not present? In the future, we may even want to add the state's attributes through a UI since it gives us the flexibility to propose a transaction we want rather than have it hard-coded. Any idea if this could be possible in future releases?
See the Negotiation Cordapp sample for an example of how this would work in practice here.
Suspending a flow for human interaction isn't currently implemented (as of Corda V3.0).
Instead, you'd implement this by adding a status flag to your state:
class FooState(
override val participants: List<Party>,
val accepted: Boolean) : ContractState
You'd have three commands:
interface Commands : CommandData {
class Propose : Commands
class Reject: Commands
class Accept: Commands
}
And two flows:
A proposal flow: In this flow, the initiator creates and signs a Propose transaction to issue the state onto the ledger with a Propose command and the accepted flag set to false
An accept flow: In this flow, the recipient either:
Creates a Reject transaction that consumes the proposed state and outputs nothing. The state has been removed from the ledger and is effectively rejected
Creates an Accept transaction that updates the proposed state so that accepted is true. The state has now been accepted, and this fact is registered on the ledger
You'd give the accept flow a parameter which determines whether or not to accept the proposal. This parameter would be provided by the user when the flow is kicked off either via an API or directly over RPC.
I have following flow in my Mule app:
<flow name="UpdateStatusFlow">
<vm:inbound-endpoint path="UpdateStatusFlow" exchange-pattern="request-response"/>
<async processingStrategy="asynchronous">
<request-reply>
<vm:outbound-endpoint path="request"/>
<vm:inbound-endpoint path="reply"/>
</request-reply>
</async>
<custom-transformer class="com.example.EanTransformer"/>
</flow>
In async scope I depend on what has come to vm:inbound-endpoint and I assumed it is copy of that payload, so another copy is sent to EanTransformer which also modify payload. But it seems that no copy is made because in async flow I get already modified by EanTransformer ean code, which is not what I expected. If I add some delay in EanTransformer everything is fine, which means for me that this transformer haven't modify the message yet.
So the question is: if async scope really gets copy of the message (as it is written here: http://www.mulesoft.org/documentation/display/current/Async+Scope+Reference) or work on the same message as next components? Or am I doing something wrong?
I am using Mule 3.3.1.
If you read the referenced page further, it states that:
Even though the Async scope receives a copy of the Mule message, the payload is not copied. The same payload object(s) will be referenced by both Mule messages: the one that continues down the original flow and the one processed by the Async scope.
In other words, if the payload of your message is a mutable object
(for example a bean with different fields in it) and a message
processor in your async scope changes the value of one of the fields,
the message processors outside of the Async scope will see the changed
values.
The Async flow does not receive a Copy of the message - rather it receives the original payload. So any changes to the payload should be done before the Async flow. Here it is clearly written:
Even though the Async scope receives a copy of the Mule message, the payload is not copied. The same payload object(s) will be referenced by both Mule messages: the one that continues down the original flow and the one processed by the Async scope.
In other words, if the payload of your message is a mutable object (for example a bean with different fields in it) and a message processor in your async scope changes the value of one of the fields, the message processors outside of the Async scope will see the changed values.