This library aims to read and query the Trueblocks unchained index. It does not cover the generation of the index.
Run Main.kt
./gradlew runPass an address to check via:
./gradlew run --args="0xfffc3ead0df70e9bbe805af463814c2e6de5ae79"Run the tests:
./gradlew testIn settings.gradle.kts:
repositories {
maven("https://jitpack.io")
}In build.gradle.kts:
dependencies {
implementation("com.github.biafra23:trueblocks-kotlin:main-SNAPSHOT")
}Use either IpfsHttpClient or IpfsLocalClient to connect to the Trueblocks index. The IpfsHttpClient connects to a remote IPFS node via https,
while the IpfsLocalClient connects to a local IPFS node. The latter is recommended for decentralization reasons.
import com.jaeckel.trueblocks.IpfsClient
import com.jaeckel.trueblocks.IpfsHttpClient // only for HTTP
import com.jaeckel.trueblocks.IpfsLocalClient // only for IPFS
import com.jaeckel.trueblocks.SwarmConnectResult
import org.kethereum.model.Address
import kotlin.system.exitProcessUse via HTTP Gateway
val manifestCID =
"QmUBS83qjRmXmSgEvZADVv2ch47137jkgNbqfVVxQep5Y1" // version [email protected]
val ipfsClient: IpfsClient = IpfsHttpClient("https://ipfs.unchainedindex.io/ipfs/")
val manifestResponse = ipfsClient.fetchAndParseManifestUrl(manifestCID)Use via IPFS node
val manifestCID =
"QmUBS83qjRmXmSgEvZADVv2ch47137jkgNbqfVVxQep5Y1" // version [email protected]
val ipfsClient = IpfsLocalClient("http://127.0.0.1:5001/api/v0/")
// Add Pinata node for reliable IPFS access to trueblocks data
val pinataAddress = "/dnsaddr/bitswap.pinata.cloud"
val response = ipfsClient.swarmConnect(pinataAddress)
if (response is SwarmConnectResult.Success) {
logger.info("Pinata connect result: $response")
} else {
logger.error("Failed to connect to $pinataAddress: $response")
exitProcess(1)
}
// Fetch manifest
val manifestResponse = ipfsClient.fetchAndParseManifestUrl(manifestCID)The chunks section of the manifest should have entries like this:
{
"bloomHash": "QmdREgbfg2kWNYLps12G8sR1tLxDBM67nNoNevcbLVWyK5",
"bloomSize": 131114,
"indexHash": "QmevozuTsKZ2pAWw89DGQFbPhzKdDcf141Y1Qhizt5kikr",
"indexSize": 320192,
"range": "000000000-000000000"
}For each entry the bloomHash is the CID for the bloom filter file on IPFS. The indexHash is the corresponding index chunk file which contains the appearances.
val bloom = ipfsClient.fetchBloom(bloomHash, range) val addressToCheck = "0x308686553a1EAC2fE721Ac8B814De638975a276e".lowercase()
isMember = bloom.isMemberBytes(Address(addressToCheck))Please be aware that there might be false positives. Meaning: You get a hit on the bloom filter but there is no appearance in the index file. This is normal with bloom filters.
val appearances = ipfsClient.fetchIndex(cid = it.indexHash, parse = false)?.findAppearances(addressToCheck)Each appearance contains a block number and a transaction index in that block which gives you a transaction that is relevant for your address.
See Main.kt for a full example
For an example to use this on Android please have a look at: https://github.com/biafra23/AndroidPortal