Election 2020 results on the Ethereum Blockchain

A simple exercise in pulling data from the blockchain

The Associated Press is using Everipedia's OraQle software to publish U.S. Presidential election results on November 3rd, 2020. The Ethereum Oracle is powered by Chainlink.

For a fun warm up coding exercise this morning I wrote a simple Python script that uses web3.py to pull the 2020 US election results from the Ethereum blockchain.

You will need to get an Infura.io API key, or have a Geth node already online and synced with the mainnet chain to play.

Here is the app code:

It sets up a connection, loads the contract ABI, and then pulls the data per US state. It then spits out the info.

# app.py

import json
import os
import time
from web3 import Web3

# Using Infura as an ETH node
INFURA_URL = os.getenv('INFURA_URL')
# Mainnet Contract Address
AP_ELECTION_CONTRACT = '0x0792724900B551d200D954a5Ed709d9514d73A9F'


def main():
    print('Opening connection to the Ether')
    w3 = Web3(Web3.HTTPProvider(INFURA_URL))
    connected = w3.isConnected()
    if connected:
        print(f'We are connected: {connected}')
        print(f'Node Version: {w3.clientVersion}')
    else:
        return print('Not Connected to chain')

    # Get the latest block
    latest_block = w3.eth.blockNumber
    print(f'Latest Block Number: {latest_block}')

    # ### Contract ###

    # Contract compiled ABI
    with open('ap_contract_abi.json') as f:
        # Get json data
        contract_abi = json.load(f)

    # Get contract
    contract = w3.eth.contract(
        address=AP_ELECTION_CONTRACT,
        abi=contract_abi
    )

    # Details

    # Just one state
    oregon = contract.caller().presidentialWinners('OR')
    print(oregon)
    # state = {
    #     'state': 'OR',
    #     'winner': oregon[0],
    #     'time_called': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(oregon[1])),
    #     'ethereum_block': oregon[2]
    # }
    # print(f'Winner: {state}')

    # Loop through all states
    states = ["AK", "AL", "AR", "AZ", "CA", "CO", "CT", "DC", "DE", "FL", "GA", "HI", "IA", "ID", "IL", "IN", "KS",
              "KY", "LA", "MA", "MD", "ME", "MI", "MN", "MO", "MS", "MT", "NC", "ND", "NE", "NH", "NJ", "NM", "NV",
              "NY", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VA", "VT", "WA", "WI", "WV", "WY"]
    no_results = []
    for state in states:
        data = contract.caller().presidentialWinners(state)
        if data[0] == '':
            no_results.append(state)
        state_info = {
            'state': state,
            'winner': data[0],
            'time_called': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(data[1])),
            'ethereum_block': data[2]
        }
        print(state_info)
    print(f'States without results: {no_results}')


if __name__ == '__main__':
    main()

The smart contract's ABI:

[{"inputs":[{"internalType":"bytes32","name":"_requestId","type":"bytes32"},{"internalType":"uint256","name":"_payment","type":"uint256"},{"internalType":"bytes4","name":"_callbackFunctionId","type":"bytes4"},{"internalType":"uint256","name":"_expiration","type":"uint256"}],"name":"cancelRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"ChainlinkCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"ChainlinkFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"ChainlinkRequested","type":"event"},{"inputs":[{"internalType":"string","name":"_key","type":"string"}],"name":"deleteMappingElement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_requestId","type":"bytes32"},{"internalType":"bytes32","name":"_votes","type":"bytes32"}],"name":"fulfillpresidentialWinners","outputs":[],"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"string","name":"_jobId","type":"string"},{"internalType":"string","name":"_state","type":"string"}],"name":"requestPresidentialVotes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"presidentialWinners","outputs":[{"internalType":"string","name":"winner","type":"string"},{"internalType":"uint256","name":"resultNow","type":"uint256"},{"internalType":"uint256","name":"resultBlock","type":"uint256"}],"stateMutability":"view","type":"function"}]

The mainnet Ethereum address for the smart contract:

0x0792724900B551d200D954a5Ed709d9514d73A9F

Here are my results:

python ap_results.py 
Opening connection to the Ether
We are connected: True
Node Version: Geth/v1.9.9-omnibus-e320ae4c-20191206/linux-amd64/go1.13.4
Latest Block Number: 11193438
['Biden', 1604464874, 11188587]
{'state': 'AK', 'winner': '', 'time_called': '1969-12-31 16:00:00', 'ethereum_block': 0}
{'state': 'AL', 'winner': 'Trump', 'time_called': '2020-11-03 18:11:06', 'ethereum_block': 11187906}
{'state': 'AR', 'winner': 'Trump', 'time_called': '2020-11-03 18:12:40', 'ethereum_block': 11187911}
{'state': 'AZ', 'winner': 'Biden', 'time_called': '2020-11-03 23:57:14', 'ethereum_block': 11189452}
{'state': 'CA', 'winner': 'Biden', 'time_called': '2020-11-03 20:20:13', 'ethereum_block': 11188496}
{'state': 'CO', 'winner': 'Biden', 'time_called': '2020-11-03 18:45:22', 'ethereum_block': 11188064}
{'state': 'CT', 'winner': 'Biden', 'time_called': '2020-11-03 18:17:27', 'ethereum_block': 11187928}
{'state': 'DC', 'winner': 'Biden', 'time_called': '2020-11-03 18:45:22', 'ethereum_block': 11188064}
{'state': 'DE', 'winner': 'Biden', 'time_called': '2020-11-03 18:17:27', 'ethereum_block': 11187928}
{'state': 'FL', 'winner': 'Trump', 'time_called': '2020-11-03 21:41:49', 'ethereum_block': 11188878}
{'state': 'GA', 'winner': '', 'time_called': '1969-12-31 16:00:00', 'ethereum_block': 0}
{'state': 'HI', 'winner': 'Biden', 'time_called': '2020-11-03 21:08:12', 'ethereum_block': 11188717}
{'state': 'IA', 'winner': 'Trump', 'time_called': '2020-11-03 21:26:29', 'ethereum_block': 11188812}
{'state': 'ID', 'winner': 'Trump', 'time_called': '2020-11-03 20:26:55', 'ethereum_block': 11188525}
{'state': 'IL', 'winner': 'Biden', 'time_called': '2020-11-03 18:17:35', 'ethereum_block': 11187929}
{'state': 'IN', 'winner': 'Trump', 'time_called': '2020-11-03 18:13:02', 'ethereum_block': 11187914}
{'state': 'KS', 'winner': 'Trump', 'time_called': '2020-11-03 19:08:04', 'ethereum_block': 11188162}
{'state': 'KY', 'winner': 'Trump', 'time_called': '2020-11-03 16:28:58', 'ethereum_block': 11187452}
{'state': 'LA', 'winner': 'Trump', 'time_called': '2020-11-03 18:23:06', 'ethereum_block': 11187961}
{'state': 'MA', 'winner': 'Biden', 'time_called': '2020-11-03 18:15:06', 'ethereum_block': 11187923}
{'state': 'MD', 'winner': 'Biden', 'time_called': '2020-11-03 18:15:06', 'ethereum_block': 11187923}
{'state': 'ME', 'winner': 'Biden', 'time_called': '2020-11-04 00:14:19', 'ethereum_block': 11189532}
{'state': 'MI', 'winner': '', 'time_called': '1969-12-31 16:00:00', 'ethereum_block': 0}
{'state': 'MN', 'winner': 'Biden', 'time_called': '2020-11-03 21:32:45', 'ethereum_block': 11188848}
{'state': 'MO', 'winner': 'Trump', 'time_called': '2020-11-03 20:30:57', 'ethereum_block': 11188542}
{'state': 'MS', 'winner': 'Trump', 'time_called': '2020-11-03 18:13:02', 'ethereum_block': 11187914}
{'state': 'MT', 'winner': 'Trump', 'time_called': '2020-11-03 21:41:49', 'ethereum_block': 11188878}
{'state': 'NC', 'winner': '', 'time_called': '1969-12-31 16:00:00', 'ethereum_block': 0}
{'state': 'ND', 'winner': 'Trump', 'time_called': '2020-11-03 18:24:18', 'ethereum_block': 11187967}
{'state': 'NE', 'winner': 'Trump', 'time_called': '2020-11-03 18:24:47', 'ethereum_block': 11187968}
{'state': 'NH', 'winner': 'Biden', 'time_called': '2020-11-03 20:41:14', 'ethereum_block': 11188587}
{'state': 'NJ', 'winner': 'Biden', 'time_called': '2020-11-03 18:15:06', 'ethereum_block': 11187923}
{'state': 'NM', 'winner': 'Biden', 'time_called': '2020-11-03 18:15:06', 'ethereum_block': 11187923}
{'state': 'NV', 'winner': '', 'time_called': '1969-12-31 16:00:00', 'ethereum_block': 0}
{'state': 'NY', 'winner': 'Biden', 'time_called': '2020-11-03 18:14:45', 'ethereum_block': 11187920}
{'state': 'OH', 'winner': 'Trump', 'time_called': '2020-11-03 21:35:14', 'ethereum_block': 11188852}
{'state': 'OK', 'winner': 'Trump', 'time_called': '2020-11-03 18:13:11', 'ethereum_block': 11187915}
{'state': 'OR', 'winner': 'Biden', 'time_called': '2020-11-03 20:41:14', 'ethereum_block': 11188587}
{'state': 'PA', 'winner': '', 'time_called': '1969-12-31 16:00:00', 'ethereum_block': 0}
{'state': 'RI', 'winner': 'Biden', 'time_called': '2020-11-03 18:18:15', 'ethereum_block': 11187933}
{'state': 'SC', 'winner': 'Trump', 'time_called': '2020-11-03 18:13:11', 'ethereum_block': 11187915}
{'state': 'SD', 'winner': 'Trump', 'time_called': '2020-11-03 18:24:47', 'ethereum_block': 11187968}
{'state': 'TN', 'winner': 'Trump', 'time_called': '2020-11-03 18:13:11', 'ethereum_block': 11187915}
{'state': 'TX', 'winner': 'Trump', 'time_called': '2020-11-03 22:08:53', 'ethereum_block': 11188986}
{'state': 'UT', 'winner': 'Trump', 'time_called': '2020-11-03 20:41:14', 'ethereum_block': 11188587}
{'state': 'VA', 'winner': 'Biden', 'time_called': '2020-11-03 18:24:54', 'ethereum_block': 11187970}
{'state': 'VT', 'winner': 'Biden', 'time_called': '2020-11-03 18:18:15', 'ethereum_block': 11187933}
{'state': 'WA', 'winner': 'Biden', 'time_called': '2020-11-03 21:06:40', 'ethereum_block': 11188712}
{'state': 'WI', 'winner': 'Biden', 'time_called': '2020-11-04 11:25:15', 'ethereum_block': 11192562}
{'state': 'WV', 'winner': 'Trump', 'time_called': '2020-11-03 18:01:23', 'ethereum_block': 11187863}
{'state': 'WY', 'winner': 'Trump', 'time_called': '2020-11-03 18:24:54', 'ethereum_block': 11187970}
States without results: ['AK', 'GA', 'MI', 'NC', 'NV', 'PA']

You can read more about it here: https://docs.everipedia.org/eth/fetch-election-calls-with-web3 or see the data live with their app here: https://everipedia.org/oraqle/ap/eth

The AP is posting results with this public key:
https://etherscan.io/address/0x436ee8cb3a351893b77f8b57c9772daec3a96445