Blockchain, APIs and Quest for Astrocat ?

Blockchain and dApps are hot topics these days. All of us live in the world of API services, where API providers pay $$ for cloud hosting and API consumers experience varying levels of API speed, quality, reliability and documentation level. With the ORE protocol by AIKON, APIs and blockchain work together without extra effort and API.market is where service providers and API consumers can benefit from full transparency.

In brief, ORE Protocol is about computations and quality APIs. It operates with CPU tokens and ORE tokens.

  • CPU tokens are required for API consumers and can be exchanged for cloud processing power, operating in a similar way as cloud hosting services like AWS and GCP
  • ORE tokens are required for API providers as proof of the quality of the product. For a real deep dive into ORE Protocol please refer to AIKON’s ORE whitepaper.

API.market is powered by ORE Protocol and provides developers with a simplified API rights management protocol, stable payment tokens and proof of the API quality and reliability.

I decided to try API.market myself by participating in API.market’s Deep Space Bounty Hunters contest. The contest is really simple and fun to take part in — just register with your GitHub account at API.market and get 30 CPUs for your API calls of HADRON.cloud AI API. AI is trained on terrestrial objects and is guessing what terrestrial objects it is seeing in space photos! So, you need to use the tokens to hunt for specific objects from the Hubble Telescope photos, then publish your results and earn ORE tokens. During last week’s “Quest for Astrocat” contest hunters were tasked with searching for cats on these images from space.

If you have a laptop and know what GitHub and Node.js is, you know more than enough to participate in the contest. There is a pretty decent video tutorial on how to setup the API and do your first Node.js application using API.market features and HADRON.cloud API. It only took me ~20 minutes in total to join, walk through the tutorial, watch the 15 minute video and get started using HADRON API for image recognition. Note that using the API.market JavaScript library to interact with the Aikon marketplace requires Node.js 10.4 or later. I used Node.js 10.6 and had no issues with it.

As instructed by the tutorial, I started with the provided application code, however, I changed it slightly and put full image URI, including bucket path:

const { ApiMarketClient } = require('@apimarket/apimarket')
const config = require("./apimarket_config.json");
 
const run = async () => {
   try {
       //Config to apimarketClient and connect to ORE blockchain
       let apimarketClient = new ApiMarketClient(config);
       await apimarketClient.connect()
 
       //specify the api to call using it's unique name registered on the ORE blockchain
       const apiName = "cloud.hadron.contest-2018-07"
 
       //call api - passing in the data it needs
       const params = {"imageurl":"http://storage.googleapis.com/apimarket-contest-2018-07-1-coffee/11189_full_jpg.jpg"}
       const response = await apimarketClient.fetch(apiName, params)
       console.log(JSON.stringify(response, null, 2))
 
   }
   catch(error) {
       console.error(error)
   }
}
 
run()

Running the script resulted in an error in console:

node index.js
1.0000 CPU
{ FetchError: invalid json response body at https://contest-hadron-dot-partner-aikon.appspot.com/contest-1?imageurl=http%3A%2F%2Fstorage.googleapis.com%2Fapimarket-contest-2018-07-1-coffee%2F15502_full_jpg.jpg reason: Unexpected token e in JSON at position 0
    at /Users/smasyutin/projects/Lohika/aikon-deep-space-bounty-challenge/node_modules/node-fetch/lib/index.js:239:32
    at process._tickCallback (internal/process/next_tick.js:68:7)
  message:
   'invalid json response body at https://contest-hadron-dot-partner-aikon.appspot.com/contest-1?imageurl=http%3A%2F%2Fstorage.googleapis.com%2Fapimarket-contest-2018-07-1-coffee%2F15502_full_jpg.jpg reason: Unexpected token e in JSON at position 0',
  type: 'invalid-json' }

After checking with Team AIKON, they advised that they only supported relative path images. However, within three hours, full URI support was added and rolled out onto production – a very impressive pace for the production fix!

I performed 2 API calls before I found the reason why my API calls failed. After this, my CPU count was 28 and there were still no API calls registered on my API.market dashboard, until I got a successful one.
cpu
apis

I contacted team AIKON about this and they acknowledged that they are aware of the inconsistency issue (when the last API call fails). They assured me that all the counters are correct on blockchain side and that they will be rolling out the production fix fairly soon.

Right after the first successful API call I got +200 ORE tokens as a bonus!

Then, while having just 28 API calls, I needed to find a cat on a set of 100 images provided. I decided to randomly choose 25 images and test my luck. However, I’m a fairly lazy when it comes to manual work, so instead of running the same script with different parameters 25 times in console, I modified the original sample code to loop over the provided image list and then analyze all the results. You can check full version of this code on GitHub.

const bucket = "http://storage.googleapis.com/apimarket-contest-2018-07-1-coffee";
 
const files = [
   "16481_full_jpg",
   "16385_full_jpg",
   "12057_full_jpg",
   "9983_print",
   "6966_print",
   "3707_full_jpg",
   "2793_web_print",
   "3707_full_jpg",
   "915_full_jpg",
   "207_full_jpg",
   "922_full_jpg",
];
 
const run = async (bucket, files) => {
   try {
       //Config to apimarketClient and connect to ORE blockchain
       let apimarketClient = new ApiMarketClient(config);
       await apimarketClient.connect();
 
       //specify the api to call using it's unique name registered on the ORE blockchain
       const apiName = "cloud.hadron.contest-2018-07";
 
       files.forEach(async (file) => {
           const params = {"imageurl":`${bucket}/${file}.jpg`};
           //call api - passing in the data it needs
           const response = await apimarketClient.fetch(apiName, params);
           console.log(`Execution for ${file} \n${JSON.stringify(response, null, 2)}\n`);
       });
   }
   catch(error) {
       console.error(error);
   }
};

However, this was not working for me and I got an exception:

api < error      undefined http://ore1.openrights.exchange:8684/v1/chain/push_transaction {"compression":"none","transaction":{"expiration":"2018-08-06T04:07:01","ref_block_num":6342,"ref_block_prefix":1710360376,"net_usage_words":0,"max_cpu_usage_ms":0,"delay_sec":0,"context_free_actions":[],"actions":[{"account":"token.ore","name":"approve","authorization":[{"actor":"4zdonbygm2tq","permission":"active"}],"data":"60b390cc9f49d327a02e0557b9e5aeda10270000000000000443505500000000"}],"transaction_extensions":[]},"signatures":["SIG_K1_K4JwTYktHPhixnd4cfnkmUktLYEFncNzFVPfWgd3LeSy5JQGsrs5mf3UmKeWKdCL7LR4CJSPW15qGPenzCEGaeSQu8ncN8"]}
{ Error: {"code":409,"message":"Conflict","error":{"code":3040008,"name":"tx_duplicate","what":"Duplicate transaction","details":[]}}
    at /Users/smasyutin/projects/Lohika/aikon-deepspace-challenge/node_modules/eosjs-api/lib/apigen.js:95:23
    at process._tickCallback (internal/process/next_tick.js:68:7) status: 409, statusText: 'Conflict' }
[push_transaction error] '{"code":409,"message":"Conflict","error":{"code":3040008,"name":"tx_duplicate","what":"Duplicate transaction","details":[]}}', transaction '65c9675bc6183807f26500000000010000509782a920cd000000406d7a6b350160b390cc9f49d32700000000a8ed32322060b390cc9f49d327a02e0557b9e5aeda1027000000000000044350550000000000'
{"code":409,"message":"Conflict","error":{"code":3040008,"name":"tx_duplicate","what":"Duplicate transaction","details":[]}}
(node:6778) UnhandledPromiseRejectionWarning: {"code":409,"message":"Conflict","error":{"code":3040008,"name":"tx_duplicate","what":"Duplicate transaction","details":[]}}
(node:6778) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:6778) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Team AIKON was very responsive and explained me that this is because I performed the calls in a very speedy manner. To remedy this I changed code to use a standard for loop, and added a 100 ms delay between API calls then it worked fine. This means 10 transactions per second for each client which is the current limit of the platform. Team AIKON shared with me that there is a planned increase of speed to 25 transactions per second coming next week and the significant boost of speed up to 100 transactions per second is planned by the end of this year. The final version of the code is available on GitHub.

for (let i = 0; i < files.length; i++) {
   const file = files[i];
 
   const params = {"imageurl":`${bucket}/${file}.jpg`};
   //call api - passing in the data it needs
   const response = await apimarketClient.fetch(apiName, params);
   console.log(`Execution for ${file} \n${JSON.stringify(response, null, 2)}\n`);
 
   // delay for 100 ms to prevent transaction override exception:
   // previous transaction must complete before we start a new one
   await delay(100);
}

So far my best luck in astrocat hunting resulted in a score of 0.000937631 for “tiger cat” for image 207_full_jpg.

To summarize my experience as an API consumer: Finding cats in space is not a trivial task and the API.market contest makes it fun. Still, there are some issues on the platform and team Aikon is very responsive and fixes them promptly. With API.market developers can easily find reliable services for building their decentralized apps, and companies that sell their services via API with the help of ORE protocol can easily turn them into a blockchain-enabled dService. This is a real game changer in the blockchain world!

So far, I have experimented as an API consumer, participated in developer’s surveys and earned 525 ORE tokens. Right now I have no idea how much is it? However, it should allow me to take things one step further — publish one of our R&D APIs on the API.market and see what can I do with 525 ORE tokens. This is my next task in my API.market journey and I will share my experience as an API publisher as well as how API.market can help our clients in a dedicated blog post soon.

Stay tuned and feel free to subscribe to AIKON newsletter and telegram.