Is it possible to getting transaction consumed time which can be seen in vault_state through vault query?
Yes. You can find the time the state was consumed using the statesMetadata field of the query result.
Within a flow:
#Suspendable
override fun call() {
val results = serviceHub.vaultService.queryBy(ContractState::class.java)
val statesAndMetadata = results.states.zip(results.statesMetadata)
statesAndMetadata.forEach { (stateAndRef, metadata) ->
val consumedTime = metadata.consumedTime
}
}
Within an RPC client:
fun main(args: Array<String>) {
require(args.size == 1) { "Usage: TemplateClient <node address>" }
val nodeAddress = parse(args[0])
val client = CordaRPCClient(nodeAddress)
// Can be amended in the com.template.MainKt file.
val cordaRPCOps = client.start("user1", "test").proxy
val results = cordaRPCOps.vaultQueryBy<ContractState>()
val statesAndMetadata = results.states.zip(results.statesMetadata)
statesAndMetadata.forEach { (stateAndRef, metadata) ->
val consumedTime = metadata.consumedTime
}
}
Related
I have a Firebase Database with several purchases in Android app, points value is assigned for each purchase, then entries are showing by following way:
When userId is log in, a button appears and when user click on it the "showInfoClient" function is called and it must show user and the amount of points. Code is:
private val database = Firebase.database
private val myref = database.getReference("compras")
fun showInfoClient(view: View) {
val userlog = FirebaseAuth.getInstance().currentUser?.displayName
val alertDialogInfo = AlertDialog.Builder(this).create()
myref.orderByChild("userId").equalTo(userlog).addListenerForSingleValueEvent(object :
ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
var sum = 0
for (data in dataSnapshot.children) {
sum += data.child("puntos").getValue(Int::class.java)!!
Toast.makeText(this#Principal, sum, Toast.LENGTH_SHORT).show()
}
}
override fun onCancelled(databaseError: DatabaseError) {}
})
alertDialogInfo.setTitle(userlog)
alertDialogInfo.setMessage("Puntos: ") // + sum
alertDialogInfo.setButton(
AlertDialog.BUTTON_POSITIVE, "OK"
) { dialog, _ ->; dialog.dismiss() }
alertDialogInfo.show()
val btnPositive = alertDialogInfo.getButton(AlertDialog.BUTTON_POSITIVE)
val layoutParams = btnPositive.layoutParams as LinearLayout.LayoutParams
layoutParams.weight = 100f
btnPositive.layoutParams = layoutParams
}
I have tried to use different options but i´m not able to set "sum" value on
alertDialogInfo.setMessage("Puntos: $sum")
Thanks in advance
Any code that needs data from the database needs to be inside onDataChange or be called from there. Code outside of onDataChange will (most likely) run before the data is loaded.
So:
val userlog = FirebaseAuth.getInstance().currentUser?.displayName
val alertDialogInfo = AlertDialog.Builder(this).create()
myref.orderByChild("userId").equalTo(userlog).addListenerForSingleValueEvent(object :
ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
var sum = 0
for (data in dataSnapshot.children) {
sum += data.child("puntos").getValue(Int::class.java)!!
}
alertDialogInfo.setTitle(userlog)
alertDialogInfo.setMessage("Puntos: ") // + sum
alertDialogInfo.setButton(
AlertDialog.BUTTON_POSITIVE, "OK"
) { dialog, _ ->; dialog.dismiss() }
alertDialogInfo.show()
val btnPositive = alertDialogInfo.getButton(AlertDialog.BUTTON_POSITIVE)
val layoutParams = btnPositive.layoutParams as LinearLayout.LayoutParams
layoutParams.weight = 100f
btnPositive.layoutParams = layoutParams
}
override fun onCancelled(databaseError: DatabaseError) {
throw databaseError.toException(); // never ignore errors
}
})
For a longer explanation see:
getContactsFromFirebase() method return an empty list
Setting Singleton property value in Firebase Listener
I already tried suggestions from other posts but no success.
I just run into an issue,I got the following code which displays data from Firebase database when user clicks on a specific date.If I comment out (startAt(),endAt()), the recycler gets populated with all data, when I add equalTo() or startAt().endAt()) recycler does not get populated.
The code before was working normally, just recently stopped working and I have no clue why.
The code looks like this:
Bellow is the adapter:
fun calendarAdapt(options:FirebaseRecyclerOptions<ModelCalendar>,dataref:
DatabaseReference,context: Context):FirebaseRecyclerAdapter<ModelCalendar,CalendHold>{
return object :FirebaseRecyclerAdapter<ModelCalendar,CalendHold>(options){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CalendHold {
return
CalendHold(LayoutInflater.from(parent.context).inflate(R.layout.list_row_calendar,parent,false))
}
override fun onBindViewHolder(holder: CalendHold, positionc: Int, modelc: ModelCalendar)
{
val postkeyC= getRef(positionc).key
dataref.child(postkeyC!!).addValueEventListener(object:ValueEventListener{
override fun onDataChange(dataSnapshot: DataSnapshot) {
holder.bindlogC(modelc)
}
override fun onCancelled(p0: DatabaseError) {
}
})
}
}
}
This is the Query:
fun query2(cont: LifecycleOwner,selected_date:String):FirebaseRecyclerOptions<ModelCalendar>{
val queryy = FirebaseDatabase.getInstance()
.reference
.child("Ev")
.startAt(selected_date)
.endAt(selected_date)
return FirebaseRecyclerOptions.Builder<ModelCalendar>()
.setQuery(queryy,ModelCalendar::class.java)
.setLifecycleOwner(cont)
.build()
}
Here I apply the adaptor:
mDb = FirebaseDatabase.getInstance().reference.child("Ev")
val c = Calendar.getInstance()
val year2 = c.get(Calendar.YEAR)
val month2 = c.get(Calendar.MONTH)
val day2 = c.get(Calendar.DAY_OF_MONTH)
val dayd= checkDigit(day2)
val monthd= checkDigit(month2+1)
val datetoday = java.lang.StringBuilder()
.append(dayd)
.append("-")
.append(monthd)
.append("-")
.append(year2)
calendinf(datetoday.toString())
calendarid.setOnDateChangeListener { view, year, month, dayOfMonth ->
val month = checkDigit(month+1)
val day = checkDigit(dayOfMonth)
val datesel =StringBuilder()
.append(day)
.append("-")
.append(month)
.append("-")
.append(year)
calendinf(datesel.toString())
}
}
private fun calendinf(selected_date:String){
val options = Queryess().query2(this,selected_date)
val adaptorC = Adaptall().calendarAdapt(options, mDb,this)
calerec!!.adapter=adaptorC!!
}
I fix-it,It was the query, was missing "orderBychild()" field, most probable I mistakenly deleted otherwise cannot explain-it :))
I am doing some reporting kind of things using customer query. for that, i have to fetch the data from respective node's database.but,no clue how to do that.its normally fetching all data irrespective of node.
Let's do an example based on the IOU CorDapp (https://github.com/corda/cordapp-example/). There are several ways you can do this:
1. Via an API endpoint
This endpoint will return any IOUs stored on the node with a value above minValue:
#GET
#Path("ious-above-value")
#Produces(MediaType.APPLICATION_JSON)
fun getIOUsAboveValue(#QueryParam("minValue") minValue: Int): List<IOUState> {
val results = builder {
val currencyIndex = IOUSchemaV1.PersistentIOU::value.greaterThan(minValue)
val customCriteria = QueryCriteria.VaultCustomQueryCriteria(currencyIndex)
rpcOps.vaultQueryBy<IOUState>(customCriteria)
}
val stateAndRefs = results.states
return stateAndRefs.map { stateAndRef -> stateAndRef.state.data }
}
2. Via a client
This client will return any IOUs stored on the node with a value above minValue:
fun main(args: Array<String>) {
require(args.size == 1) { "Usage: ExampleClientRPC <node address>" }
val nodeAddress = NetworkHostAndPort.parse(args[0])
val client = CordaRPCClient(nodeAddress)
// Can be amended in the com.example.MainKt file.
val proxy = client.start("user1", "test").proxy
val results = builder {
val currencyIndex = IOUSchemaV1.PersistentIOU::value.greaterThan(3)
val customCriteria = QueryCriteria.VaultCustomQueryCriteria(currencyIndex)
proxy.vaultQueryBy<IOUState>(customCriteria)
}
val stateAndRefs = results.states
val states = stateAndRefs.map { stateAndRef -> stateAndRef.state.data }
}
3. Via the node's database directly
You can log into the node's database by following the instructions here: https://docs.corda.net/node-database.html. You will then be able to execute SQL queries against the node's database directly.
Corda 2.0
JDK 1.8.0_162
I'm trying to debug an inconsistent behaviour in FinalityFlow. Inconsistent as in different results in Mock and Real nodes.
The Procedure on Real Nodes
I'm trying to send a transaction to another node through one of the alternative FinalityFlow constructors:
constructor(transaction: SignedTransaction, extraParticipants: Set<Party>) : this(transaction, extraParticipants, tracker())
I communicate with my node through RPC. The procedure starts by retreiving the other node's Party by it's name, eg. O=PartyA,L=London,C=GB:
val extraRecipientParties = myExtraRecipientsStringList.map { rpcOps.wellKnownPartyFromX500Name(CordaX500Name.build(X500Principal(it)))!! }
Then, rpcOps calls the flow responsible for creating a state:
val flow = rpcOps.startFlow(::CreateStateFlow, other, arguments, extraRecipientParties)
val result = flow.returnValue.getOrThrow()
val newState = result.tx.outRef<MyStateClass>(0)
CreateStateFlow is pretty standard:
#StartableByRPC
class CreateStateFlow(
val s: String,
val p: String,
val o: String,
val extraParticipants: List<Party>
) : FlowLogic<SignedTransaction>() {
constructor(s: String, p: String, o: String): this(s, p, o, emptyList())
#Suspendable
override fun call() : SignedTransaction {
val notary = serviceHub.networkMapCache.notaryIdentities.first()
val newState = MyStateClass(ourIdentity, s, p, o, extraRecipients=extraParticipants)
val command = Command(TripleContract.Create(), listOf(ourIdentity.owningKey))
val outputState = StateAndContract(newState, TripleContract.CONTRACT_REF)
val utx = TransactionBuilder(notary=notary).withItems(
command,
outputState
)
val stx = serviceHub.signInitialTransaction(builder=utx, signingPubKeys=listOf(ourIdentity.owningKey))
if (newState.extraRecipients.isEmpty()) {
return subFlow(FinalityFlow(stx))
}
return subFlow(FinalityFlow(stx, newState.extraRecipients.toSet() ))
}
}
What I expect is that now, on any node owned by parties in the extraRecipients variable, I should be able to find newState by querying the vault.
Indeed, this is true when I test it on Mock nodes, but not when rpc calls
rpcOps.vaultQueryBy<MyStateClass>().states --> returns an empty list
Test on Mock Nodes
#Test
fun `FinalityFlow used to federate a transaction`(){
val partyAString = node1.info.legalIdentities.first().name.toString()
val aStringX500Name = CordaX500Name.build(X500Principal(partyAString))
val node2FindPartyA = node2.rpcOps.wellKnownPartyFromX500Name(aStringX500Name)!!
assert(node1.info.legalIdentities.contains(node2FindPartyA))
val executingFlow = node2.start(CreateStateFlow("fo", "boo", "bar", listOf(node2FindPartyA)))
val flowResult = executingFlow.getOrThrow()
val stateInNode2 = flowResult.tx.outRef<MyStateClass>(0)
val stateInNode1 = node1.database.transaction {
node1.services.loadState(stateInNode2.ref)
}
assert(stateInNode1.data == stateInNode2.state.data)
Edit:
MyStateClass.kt
data class MyStateClass(
val owner: Party,
val s: String,
val p: String,
val o: String,
val extraRecipients: List<Party>,
val lastEditor: AbstractParty = owner,
override val participants: List<AbstractParty> = listOf(owner),
override val linearId: UniqueIdentifier = UniqueIdentifier()
) : LinearState, QueryableState {
object MyStateSchemaV1 : MappedSchema(MyStateClass::class.java, 1, listOf(MyStateEntity::class.java)) {
#Entity
#Table(name = "my-state")
class MyStateEntity(state: MyStateClass) : PersistentState() {
#Column #Lob
var owner: ByteArray = state.owner.owningKey.encoded
#Column
var s: String = state.s
#Column
var p: String = state.p
#Column
var o: String = state.o
#Column #ElementCollection
var extra_recipients: Set<ByteArray> = state.extraRecipients.map { it.owningKey.encoded }.toSet()
#Column #ElementCollection
var participants: Set<ByteArray> = state.participants.map { it.owningKey.encoded }.toSet()
#Column #Lob
var last_editor: ByteArray = state.owner.owningKey.encoded
#Column
var linear_id: String = state.linearId.id.toString()
}
}
override fun supportedSchemas(): Iterable<MappedSchema> = listOf(MyStateSchemaV1)
override fun generateMappedObject(schema: MappedSchema): PersistentState = MyStateSchemaV1.MyStateEntity(this)
}
Although you introduced a new variable val extraRecipients: List<Party>, your participants is only on the owner, override val participants: List<AbstractParty> = listOf(owner) Therefore only the owner party should have the state in the vault.
The extraRecipients in FinalityFlow do not store the states in the vault (states storage), but they store the copy of the notarised transaction in the transaction storage.
The definition of loadState function is Given a [StateRef] loads the referenced transaction and looks up the specified output [ContractState]. Because node 1 was added as a extra recipient of the transaction in finality flow (think of it as the cc-ed recipient of an email), when asked to loadState, it was able to deduce the state from the transaction storage since it consists of inputs, commands, outputs, etc. So here you've proven that the transaction was sent to the other parties during FinalityFlow.
While on the rpcOps.vaultQueryBy<MyStateClass>().states, it was actually querying states from the node states vault - not transaction storage, therefore returned an empty list.
If you want the extraRecipients to store the state, you'll need to add them in the participants field of the state or use observable-states concept here.
I need to know when the new state got committed into the node's vault for getting the timestamp at that moment. So, I think if I can handle the committed state then trigger my timestamp record class would be nice.
By the way, please let me know if you have any suggestions about capturing timestamp on state evolving over time.
Yes, you can do this using the CordaRPCOps.vaultTrackBy method. This method returns an observable of updates to the vault. You can subscribe to this observable to be notified whenever a new state is recorded in the vault.
RPC example
fun main(args: Array<String>) {
require(args.size == 1) { "Usage: ExampleClientRPC <node address>" }
val nodeAddress = NetworkHostAndPort.parse(args[0])
val client = CordaRPCClient(nodeAddress)
val rpcOps = client.start("user1", "test").proxy
val updates = rpcOps.vaultTrackBy<ContractState>().updates
// Log the 'placed' IOU states and listen for new ones.
updates.toBlocking().subscribe { update ->
update.produced.forEach { stateAndRef ->
val timeStamp = Instant.now()
// TODO("Use the timestamp as you wish.")
}
}
}
Flow test example
class FlowTests {
lateinit var network: MockNetwork
lateinit var a: StartedMockNode
lateinit var b: StartedMockNode
#Before
fun setup() {
network = MockNetwork(
listOf("com.example.contract"),
// We need each node to operate on a separate thread so that we can
// subscribe to the vault updates on a separate thread later.
threadPerNode = true)
a = network.createPartyNode()
b = network.createPartyNode()
listOf(a, b).forEach { it.registerInitiatedFlow(ExampleFlow.Acceptor::class.java) }
}
#After
fun tearDown() {
network.stopNodes()
}
#Test
fun `flowTest`() {
// Trying to access the node database in a separate thread would result in a
// `java.lang.IllegalStateException: Was expecting to find CordaPersistence set on current thread` exception
val updates = a.services.vaultService.trackBy<ContractState>().updates
Thread {
updates.toBlocking().subscribe { update ->
update.produced.forEach { stateAndRef ->
val timeStamp = Instant.now()
// TODO("Use the timestamp as you wish.")
}
}
}.start()
repeat(3) {
val flow = ExampleFlow.Initiator(1, b.info.singleIdentity())
a.startFlow(flow).getOrThrow()
}
// We give the other thread time to observe the updates.
Thread.sleep(10000)
}
}