On Thursday 27 and Friday 28 July we attended the WeAreDevelopers World Congress in Berlin to spread the good word about trustworthy data. And what better way to demonstrate the value of trustworthy data and transparency than with a little friendly competition where the integrity, transparency and trustworthiness of your data could be the key to winning a fantastic prize?
In this voting use case we prove the value of public attestations and transparent claims with a tamper proof game of ‘guess the number of jelly beans in the jar’.
Step 1: Answer pre-commitment
To ensure we couldn’t cheat, we committed to the answer before voting opened! In a 21st Century version of “we sealed the answer in an envelope backstage”, we attested the answer on Instaproof before the voting opened. By making a ‘hash-only’ public attestation of the result we were able to commit proof of the answer without actually revealing the answer itself… until after the contest was over. Accountability is compatible with privacy!
This makes the vote provably fair with some quite neat properties:
- immutability: we can’t change it later
- non-repudiation: we can’t deny it later
- non-equivocation: we can’t publish lots of answers and choose the one we like best: we’re held accountable to a single answer
Step 2: Collecting the votes
Clearly our second challenge was too easy as loads of people made app credentials and took to the API to claim their 9 extra chances at winning. This was great to see as it’s not always easy to get started with an authenticated API but the great professionals at WeAreDevelopers took it in their stride! A few people did struggle and came to us for help, including one very dedicated chap who did the whole thing on his phone!
There were almost 600 guesses made over the two days with great curiosity and participation from the conference attendees. It was great meeting and talking to you all 🙂
Step 3: Publishing the answer… and proving we didn’t cheat!
Once voting closed we published this file (below) with the answer in. You can verify for yourself that this was the answer we pre-committed by downloading it (button below) and dragging it onto Instaproof right now…
What are you actually seeing when you verify this file on Instaproof? Take a look:
Now for the big one… who won?
Strictly speaking we don’t even need to be involved in finding the winner: anyone in the world can audit this transparent voting process! And in fact they did! Keep reading to see what happened there. But in keeping with our SaaS philosophy, we’ve done the work so you don’t have to 😃
Step 1: Finding the closest guess(es)
If someone had guessed correctly then finding the winner would have been a one-liner:
curl -X GET 'https://app.rkvst.io/archivist/v2/publicassets/-/events?event_attributes.vote_value=3597' | jq
Unfortunately nobody was spot-on so we had to look for near misses. That threw up one person who missed with an error margin of just one bean!
Step 2: Check they voted within the voting window
Every RKVST event includes an immutable timestamp as well as its inclusion on the ledger, so we can verify for sure that the winning vote was cast in time. While we’re here we can also check who cast the vote by looking at the privacy-preserving identity information in the payload:
{
"identity": "publicassets/9bda7ba3-b25b-4038-827f-859eb0edd5a7/events/de1ace7a-6960-41b6-87d7-bf930b040271",
"asset_identity": "publicassets/9bda7ba3-b25b-4038-827f-859eb0edd5a7",
"event_attributes": {
"arc_description": "Cast a vote",
"arc_display_type": "Vote",
"vote_value": "3598"
},
"asset_attributes": {},
"operation": "Record",
"behaviour": "RecordEvidence",
"timestamp_declared": "2023-07-28T13:08:28Z",
"timestamp_accepted": "2023-07-28T13:08:28Z",
"timestamp_committed": "2023-07-28T13:08:28.902593239Z",
"principal_declared": {
"issuer": "",
"subject": "",
"display_name": "",
"email": ""
},
"principal_accepted": {
"issuer": "",
"subject": "",
"display_name": "",
"email": ""
},
"confirmation_status": "CONFIRMED",
"transaction_id": "",
"block_number": 0,
"transaction_index": 0,
"from": "0x5f751FA04A7d13C8Df0e0f38e9e887C0eB6FA99e",
"tenant_identity": "tenant/aaae1d08-6c81-41cb-8e82-9a3f6bae09e7"
},
So, tenant/aaae1d08-6c81-41cb-8e82-9a3f6bae09e7
cast their vote at 13:08 on Friday – well inside the window!
Step 3: Check they didn’t exceed their quota
By the rules of the game, only the first 10 votes count. And we can check! So we need to see what other guesses this account holder made. We can do that easily by looking at the whole stream of votes in their Asset:
curl -X GET 'https://app.rkvst.io/archivist/publicassets/9bda7ba3-b25b-4038-827f-859eb0edd5a7/events?event_attributes.vote_value=*' | jq '.events | length'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 998 100 998 0 0 706 0 0:00:01 0:00:01 --:--:-- 707
10
So far so good – exactly 10 votes cast! But it’s always possible that they could have created another vote feed to get another 10… and we can check that too! By auditing the entire population of votes and looking for their identity we can verify that they only had one feed:
curl -X GET 'https://app.rkvst.io/archivist/publicassets/-/events?event_attributes.vote_value=*' | jq '[.events[] | select(.tenant_identity=="tenant/ef6e8e53-a11d-4c90-9b94-c0d5ba34acaa")] | length'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 447k 0 447k 0 0 422k 0 --:--:-- 0:00:01 --:--:-- 424k
10
OK, all good! Looks like they’ve won!
Step 4: Award the prize!
So the winner was Kiley.Smitham. Congratulations! 🎉 Of course we don’t publish their real name here – transparency and accountability come in balance with personal privacy…
Footnote: last-minute controversy!
There was some good-natured controversy when one very keen competitor came to see if we’d actually been deleting results. He had collected and audited the entire process and thought that we’d deleted some older votes from the data set.
Obviously this would be very bad, so cue an emergency debug/pair programming exercise with our Chief Product and Technology Officer to find out where this impression came from, and the answer was… paging! Our API will never return more than 500 results no matter how many more you ask for, so you have to use page tokens to fetch older records.