How to set static ip, gateway, dns1 and 2 on android 10? - deprecated

WifiConfiguration is deprecated and stopped working in API 29
wifiManager.configuredNetworks now returns null
On previous android version I was able to use the below solution using WifiConfiguration
`fun setStaticIpConfiguration(manager: WifiManager, config: WifiConfiguration, ipAddress: InetAddress?, prefixLength: Int, gateway: InetAddress, dns: Array<InetAddress?>) { // First set up IpAssignment to STATIC.
val ipAssignment = getEnumValue("android.net.IpConfiguration\$IpAssignment", "STATIC")
callMethod(config, "setIpAssignment", arrayOf("android.net.IpConfiguration\$IpAssignment"), arrayOf(ipAssignment))
// Then set properties in StaticIpConfiguration.
val staticIpConfig = newInstance("android.net.StaticIpConfiguration")
val linkAddress = newInstance("android.net.LinkAddress", arrayOf(InetAddress::class.java, Int::class.javaPrimitiveType), arrayOf(ipAddress, prefixLength))
setField(staticIpConfig, "ipAddress", linkAddress)
setField(staticIpConfig, "gateway", gateway)
getField(staticIpConfig, "dnsServers", ArrayList::class.java).clear()
for (i in dns.indices) getField(staticIpConfig, "dnsServers", ArrayList::class.java).add(dns[i] as Nothing)
callMethod(config, "setStaticIpConfiguration", arrayOf("android.net.StaticIpConfiguration"), arrayOf(staticIpConfig))
val netId = manager.updateNetwork(config)
val result = netId != -1
if (result) {
val isDisconnected = manager.disconnect()
val configSaved = manager.saveConfiguration()
val isEnabled = manager.enableNetwork(config.networkId, true)
val isReconnected = manager.reconnect()
}
}
#Throws(IllegalAccessException::class, IllegalArgumentException::class, NoSuchFieldException::class)
private fun setField(`object`: Any, fieldName: String, value: Any) {
val field = `object`.javaClass.getDeclaredField(fieldName)
field[`object`] = value
}
`
The android documentation suggest NetworkSpecifier and WifiNetworkSuggestion should be used to replace WifiConfiguration but there are no methods to set ip addresses in these classes.
From API level 33 android introduced StaticIpConfiguration but my device is running on android 10

Related

(R3 Corda 4.8) Selected output constraint: net.corda.core.contracts.WhitelistedByZoneAttachmentConstraint#1f102389 not satisfying

I had cloned the cordapp-kotlin-template . I've defined a state called LoadState which looks like this:
#BelongsToContract(LoadContract::class)
data class LoadState(
val loadId: String,
val transporterName: String? = null,
val vehicleModel: String? = null,
val regLicenseNo: String? = null,
val totalWeight: Int? = null,
val notes: String? = null,
val suppliers: MutableList<SupplierDetailsModel> = mutableListOf(),
val recycler: Party,
override val participants: List<AbstractParty> = listOf(recycler)
) : QueryableState {
override fun generateMappedObject(schema: MappedSchema): PersistentState {
if (schema is LoadSchemaV1) {
return PersistentLoadState(this.loadId)
} else {
throw IllegalArgumentException("Unsupported Schema.")
}
}
override fun supportedSchemas(): Iterable<MappedSchema> {
return listOf(LoadSchemaV1())
}
}
When I use the application for the first time and issue a LoadState say LO123 it works fine. The state is issued and recorded in the vault as well.
This is how my the LoadState issue flow looks like:
#Suspendable
override fun call(): SignedTransaction {
val notary = serviceHub.networkMapCache.getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB"))
progressTracker.currentStep = TX_COMPONENTS
val recyclerName = CordaX500Name(
organisation = "MyRecycler",
locality = "Mumbai",
country = "IN"
)
val recycler = serviceHub.identityService.wellKnownPartyFromX500Name(recyclerName)
?: throw IllegalArgumentException("Could not find party Recycler.")
val outputState = LoadState(
loadId = req.loadId,
loadDate = req.loadDate,
transporterName = req.transporterName,
vehicleModel = req.vehicleModel,
regLicenseNo = req.regLicenseNo,
totalWeight = req.totalWeight,
assets = req.assets,
suppliers = req.suppliers,
recycler = recycler,
notes = req.notes
)
val command = Command(LoadContract.Commands.Create(), listOf(ourIdentity.owningKey))
progressTracker.currentStep = TX_BUILDING
val txBuilder = TransactionBuilder(notary = notary)
.addOutputState(outputState, LoadContract.ID)
.addCommand(command)
// signing the transaction
progressTracker.currentStep = TX_SIGNING
val signedTx = serviceHub.signInitialTransaction(txBuilder)
// verifying the transaction
progressTracker.currentStep = TX_VERIFICATION
txBuilder.verify(serviceHub)
// We finalise the transaction and then send it to the counterparty.
progressTracker.currentStep = FINALIZATION
val recyclerSession = initiateFlow(recycler)
return subFlow(FinalityFlow(signedTx, listOf()))
}
Now there's a requirement to add a new field to our LoadState:
val myNewField: String? = null
After adding this new field to the LoadState I'm running the deployNodes command. Once the build folders are generated I'm copying the contents of the Node/cordapps folder to my old build Node/cordapps folder.
Now, while starting the nodes I'm running the migration commands (core schemas and app schemas). Once the migration process is complete and the nodes are up, I'm calling an api endpoint which invokes a flow which takes L0123 as input, copies it, and modifies some params and create a new output state of type LoadState. The error is thrown at:
txBuilder.verify(serviceHub) in my UpdateLoadFlow. This is how my update flow looks like:
#Suspendable
override fun call(): SignedTransaction {
val notary = serviceHub.networkMapCache.getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB"))
progressTracker.currentStep = TX_COMPONENTS
val recyclerName = CordaX500Name(
organisation = "MyRecycler",
locality = "Mumbai",
country = "IN"
)
val recycler = serviceHub.identityService.wellKnownPartyFromX500Name(recyclerName)
?: throw IllegalArgumentException("Could not find party Recycler.")
val inputState = QueryVault().queryLoadById(req.loadId, Vault.StateStatus.UNCONSUMED, serviceHub.vaultService)
?: throw Exception("Load ${req.loadId} not found.")
val vaultData = inputState.state.data
var outputState = vaultData.copy(myNewField = "some new value");
val command = Command(LoadContract.Commands.Update(), listOf(ourIdentity.owningKey))
progressTracker.currentStep = TX_BUILDING
val txBuilder = TransactionBuilder(notary = notary)
.addInputState(inputState)
.addOutputState(outputState, LoadContract.ID)
.addCommand(command)
txBuilder.verify(serviceHub)
// signing the transaction
progressTracker.currentStep = TX_SIGNING
val signedTx = serviceHub.signInitialTransaction(txBuilder)
// verifying the transaction
progressTracker.currentStep = TX_VERIFICATION
// We finalise the transaction and then send it to the counterparty.
progressTracker.currentStep = FINALIZATION
val recyclerSession = initiateFlow(recycler)
return subFlow(FinalityFlow(signedTx, listOf()))
}
Please help me out with this.
After our discussion in the above comments section, it appears that your states have been issued using Whitelist zone constraint.
Also looking at the code it is clear that you have not explicitly added Whitelist Zone constraints for your states.
Then there remain two more possibilities by which states are issued using Whitelist Zone constraint.
One is you are using some Corda version before 4 or you have included the necessary configs to include white list zone constraints in network bootstrapper as specified here.
You have two options - either start from scratch and make sure you use Corda 4.
If you cannot start from scratch follow this path to first migrate the whitelist zone constraints to signature constraints, before running your UpdateLoadFlow. You can refer to this blog which talks about constraint migration.

How to setup H2 for Corda

I am re-writing and running a IssueFlow for an example cordapp here.
I can see the flow is successful and can find a number of UTXOs on the vault query for the node.
run vaultQuery contractStateType: com.example.state.IOUStat
I would like to view the data in the persistent store (H2).
I've added the following to my node's config (similar for party A node with different port).
devMode=true
myLegalName="O=PartyB,L=New York,C=US"
p2pAddress="localhost:10008"
rpcSettings {
address="localhost:10009"
adminAddress="localhost:10049"
}
security {
authService {
dataSource {
type=INMEMORY
users=[
{
password=test
permissions=[
ALL
]
user=user1
}
]
}
}
}
h2Settings {
address: "localhost:12344"
}
I can see the DB url on run-nodes
jdbc:h2:tcp://localhost:12344/node
I can successfully connect to this db url. However , I do not see any tables for my Persistent state
DB Query
object IOUSchema
object IOUSchemaV1 : MappedSchema(
schemaFamily = IOUSchema.javaClass,
version = 1,
mappedTypes = listOf(PersistentIOU::class.java)){
#Entity
#Table(name = "iou_states")
class PersistentIOU(
#Column(name = "lender")
var lenderName : String,
#Column (name = "borrower")
var borrowerName : String,
#Column(name = "value")
var value : Int,
#Column(name = "linear_id")
var linearId : UUID
) : PersistentState(){
constructor() : this("","",0, UUID.randomUUID())
}
}
#BelongsToContract(IOUContract::class)
data class IOUState (val value : Int,
val lender: Party,
val borrower : Party,
override val linearId: UniqueIdentifier = UniqueIdentifier()): LinearState, QueryableState {
override val participants : List<AbstractParty> get() = listOf(lender,borrower)
override fun generateMappedObject(schema: MappedSchema): PersistentState {
return when (schema){
is IOUSchemaV1 -> IOUSchemaV1.PersistentIOU(
this.lender.name.toString(),
this.borrower.name.toString(),
this.value,
this.linearId.id
)
else -> throw IllegalArgumentException("Unrecognised schema $schema")
}
}
override fun supportedSchemas(): Iterable<MappedSchema> = listOf(IOUSchemaV1)
}
EDIT: This certainly works by connecting directly to the file. See here, However this looks like it is connecting to a different db when using a external client (dbeaver) to connect to the JDBC url emmited on node startup.
I was unable to find tables in H2 instance as my connection string was wrong & H2 appears is creating a blank db when trying to connect to a non-existant DB.
In DBeaver , you can add the JDBC url, but it automatically pre-fixes 'jdbc:h2:'
Connection details

querying data from particular node's database

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.

Finality Flow not sending transaction to extraRecipients

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.

How could I handle event of a new state committed into the vault in a Corda node?

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)
}
}

Resources