JSON network state DOM

signature economies

library signatures

Blockchains like Ethereum Virtual Machine “EVM” systems have two important library management elements.

  • Unique identifier of a record with hash pseudo-randomness; and

  • public-private keypair signatures execute record-keeping computation.

In a traditional client-server architecture, the server holds the private key secret, not the client:

+--------+       +----------+       +---------+
| client |------>|  server  |------>| database|
+--------+       +----------+       +---------+
   |                   |                |
   |   request         |                |
   |------------------>|                |
   |                   |                |
   |                   | query          |
   |                   |--------------->|
   |                   |                |
   |                   |                |
   |                   |                |
   |                   |   result       |
   |                   |<---------------|
   |                   |                |

But in an EVM architecture, the Externally Owned Account “EOA” wallet within the client’s browser holds the private key secret:

+----------+        +-------------+        +----------+
| client   |        | signed-EOA  |        | RPC-URL  |
+----------+        +-------------+        +----------+
   |                    |                    |
   |   request          |                    |
   |------------------->|                    |
   |                    |                    |
   |                    |    query           |
   |                    |------------------->|
   |                    |                    |
   |                    |                    |
   |                    |                    |
   |                    |    result          |
   |                    |<-------------------|
   |                    |                    |

client sovereignty

EVM architecture runs on Von Neumann architecture:

+---------------------------------+
|         Central Processing Unit |
| +-----------------------------+ |
| | Arithmetic Logic Unit (ALU)| |
| +-----------------------------+ |
| | Control Unit              | |
| +-----------------------------+ |
+---------------------------------+
          |
          v
+---------------------------------+
|              Memory             |
| +-----------------------------+ |
| |     Data Memory            | |
| +-----------------------------+ |
| |     Program Memory         | |
| +-----------------------------+ |
+---------------------------------+
          |
          v
+---------------------------------+
|    Input/Output Devices        |
|                                 |
|   Keyboard, Mouse, Monitor,     |
|   Printer, etc.                 |
+---------------------------------+
          |
          v
+---------------------------------+
| Control Bus and Data Bus        |
| +-----------------------------+ |
| |      Control Bus           | |
| +-----------------------------+ |
| |       Data Bus             | |
| +-----------------------------+ |
+---------------------------------+

In a client-sovereignty model, the client runs the program and the EVM is there as the persistent data-memory & program-memory systems.

  • Onchain JavaScript Object Notation “JSON” is the client-sovereign persistent data-memory; and

  • onchain HyperText Markup Language “HTML” is the client-sovereign persistent program-memory.

The GitHub repository for the data-memory, LIFO-JSON promises, program-memory and dev environment topics below:

data-memory

The jsonState.sol smart-contract is a JSON object with Admin-only write control.

/**
 *Submitted for verification at sepolia-optimism.etherscan.io on 2023-12-27
*/

// SPDX-License-Identifier: MIT
// by besta.pe
pragma solidity ^0.8.19
;
contract jsonState {
    function KeyValue(
        string[] calldata key
        , string[] calldata value
        , bool newKeysOnly
    ) external {
        ifAdmin()
        ; uint count
        ; Change = false
        ; Replace = true
        ;
        if ( key.length != value.length ) {
            revert KeyValueNotBijective()
            ;
        }
        if ( newKeysOnly ){
            Replace = false
            ;
        }
        while( count < key.length ) {
            addKeyValue(
                key[ count ]
                , value[ count ]
            )
            ; count ++
            ;
        }
        if ( ! Change ) {
            revert NoChange()
            ;
        }
    }
    function JSON() public view returns (
        string memory
    ) {
        if ( KeyCountPlus1 == 0 ) {
            revert NoKey()
            ;
        }
        uint count
        ; string memory json = "{"
        ;
        while ( count < KeyCountPlus1 ) {
            string memory key = keyIndex[ count ].key
            ; uint version = keyIndex[ count ].version
            ; string memory value = keyValue[ 
                key ][ version 
            ].value
            ; json = string.concat(
                    json
                    , "\""
                    , key
                    , "\":\""
                    , value
                    , "\""
                )
            ;
            if ( count < KeyCountPlus1 -1 ) {
                json = string.concat(
                    json
                    , ","
                )
                ;
            }
            count++
            ;
        }
        return string.concat(
            json
            , "}"
        )
        ;
    }
    function LatestVersion(
        string calldata key
    ) public view returns ( uint ) {
        uint count
        ;
        if ( KeyCountPlus1 == 0 ) {
            revert NoKey()
            ;
        }
        while ( count < KeyCountPlus1 ) {
            if ( 
                keccak256( bytes( key ) )
                == keccak256( 
                    bytes( keyIndex[ count ].key ) 
                ) 
            ) {
                    return keyIndex[ count ].version
                    ;
            }
            count ++
            ;
        }
        revert NoKey()
        ;
    }
    function TotalKeys() public view returns (
        uint
    ) {
        if ( KeyCountPlus1 == 0 ) {
            revert NoKey()
            ;
        }   
        return KeyCountPlus1
        ;
    }
    function Value(
        string calldata key
        , uint version
    ) public view returns ( string memory ) {
        string memory value = keyValue[
            key ][ version
        ].value
        ;
        if (
            keccak256( bytes( value ) )
            == keccak256( bytes( "" ) )
        ) { 
            revert NoValue()
            ;
        }
        return value
        ;
    }
    function addKey( string calldata key ) internal {
        KeyCountPlus1 ++
        ; keyIndex[ KeyCountPlus1 -1 ] = keyMap(
            key
            , 0
        )
        ;
    }
    function addKeyValue(
        string calldata key
        , string calldata value
    ) internal {
        if (
            keccak256( bytes( key ) )
            == keccak256( bytes( "" ) )
        ) { 
            revert NoKey()
            ;
        }
        if (
            keccak256( bytes( value ) )
            == keccak256( bytes( "" ) )
        ) { 
            revert NoValue()
            ;
        }
        (
            uint index
            , uint version
        ) = newKeyTest( key )
        ;
        if ( version > 0 ) {
            if (
                keccak256( bytes( value ) )
                == keccak256( bytes( 
                    keyValue[ key ][ version -1 ].value 
                ) )
            ) {
                return
                ;
            }
            keyIndex[ index ].version += 1
            ;
        }
        keyValue[ key ][ version ] = versionMap( value )
        ; Change = true
        ;
    }
    function ifAdmin() internal view {
        if ( msg.sender == Admin ) {
            return
            ;
        }
        revert NotAdmin()
        ;
    }
    function newKeyTest(
        string calldata key
    ) internal returns (
        uint
        , uint 
    ) {
        uint count
        ;
        while ( count < KeyCountPlus1 ) {
            if (
                keccak256( bytes( key ) )
                == keccak256(
                    bytes( keyIndex[ count ].key )
                )
            ) {
                if ( ! Replace ) {
                    revert NewKeysOnly()
                    ;
                }
                return (
                    count
                    , keyIndex[ count ].version +1
                )
                ;
            }
            count ++
            ;
        }
        addKey( key )
        ; Change = true
        ; return ( 0, 0 )
        ;
    }
    mapping(
        uint => keyMap
    ) private keyIndex
    ; mapping(
        string => mapping(
            uint => versionMap
        )
    ) private keyValue
    ;
    struct versionMap {
        string value
        ;
    }
    struct keyMap {
        string key
        ; uint version
        ;
    }
    error KeyValueNotBijective()
    ; error NewKeysOnly()
    ; error NoChange()
    ; error NoKey()
    ; error NotAdmin()
    ; error NoValue()
    ; address Admin
    ; bool Change
    ; uint KeyCountPlus1
    ; bool Replace
    ;
    constructor() {
        Admin = 0x0D89421D6eec0A4385F95f410732186A2Ab45077
        ;
    }
}

Each JSON object is a standalone published smart-contract so that it has a unique top-level hash address. E.g. this smart-contract JSON object at hash address 0x8dcbc12efe584e24592d07a81bd6f6450def1052:

jsonState.sol JSON
jsonState.sol JSON

Using host.js to run index.html in the GitHub repository above:

jsonState index.html
jsonState index.html

The JSON object uses a Last-In First-Out “LIFO” value versioning array so that the key:value pairs are updatable and immutable.

jsonState.sol LatestVersion
jsonState.sol LatestVersion

LIFO-JSON promises

There is a problem in fully-web3 invoicing where too much of the result needs to be known by the request.

The JSON object’s LIFO value versioning can be used for promises similar to JavaScript promises.

For instance, this schema’s version 0 is the promise and version 1 is the return:

version 0 is the promise
version 0 is the promise
version 1 is the return
version 1 is the return

program-memory

In the GitHub repository above, the index.html HTML is a Document Object Model “DOM” small enough to store directly onchain as an iFrame NFT “iNFT” application:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>JSON State UX</title>
	<script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
	<style>
	  body {
		  font-family: Arial, sans-serif;
		  margin: 0;
		  padding: 0;
	  }
	  #config, #json, form {
		  max-width: 90%;
		  margin: 0 auto;
		  padding: 10px;
	  }
	  form label {
		  display: block;
		  margin-bottom: 5px;
	  }
	  form input[type="text"] {
		  width: 100%;
		  padding: 8px;
		  margin-bottom: 10px;
		  box-sizing: border-box;
	  }
	  button {
		  display: block;
		  width: 100%;
		  padding: 10px;
		  background-color: #007bff;
		  color: #fff;
		  border: none;
		  cursor: pointer;
	  }
	  button:hover {
		  background-color: #0056b3;
	  }
	  pre {
		  white-space: pre-wrap;
	  }
	</style>
</script>
</head>
<body>
  <div id="config">
	<div id="abi" style="display: none"></div>
  </div>
  <div id="json"></div>
  <form>
	<label for="key">contract
	  <input type="text" id="contract">
	</label>
	<br />
	<label for="key">key
	  <input type="text" id="key" value='[ "string" ]'>
	</label>
	<br />
	<label for="key">value
	  <input type="text" id="value" value='[ "string" ]'>
	</label>
	<br />
	<label for="key">newKeysOnly
	  <input type="text" id="newKeysOnly" value='true'>
	</label>
  </form>
  <button id="read">read</button>
  <br />
  <button id="write">write</button>
  <script>
	( function config() {
	    _0 = new Config
	    ; _0.div.abi.innerHTML = JSON
			.stringify(
				_0.abi
			)
	    ; _0.input.contract.value = JSON
			.stringify(
				_0.jsonState
			)
	    ;
	    function Config() {
			this.abi = [
				{
					"inputs": [],
					"stateMutability": "nonpayable",
					"type": "constructor"
				},
				{
					"inputs": [],
					"name": "KeyValueNotBijective",
					"type": "error"
				},
				{
					"inputs": [],
					"name": "NewKeysOnly",
					"type": "error"
				},
				{
					"inputs": [],
					"name": "NoChange",
					"type": "error"
				},
				{
					"inputs": [],
					"name": "NoKey",
					"type": "error"
				},
				{
					"inputs": [],
					"name": "NoValue",
					"type": "error"
				},
				{
					"inputs": [],
					"name": "NotAdmin",
					"type": "error"
				},
				{
					"inputs": [],
					"name": "JSON",
					"outputs": [
						{
							"internalType": "string",
							"name": "",
							"type": "string"
						}
					],
					"stateMutability": "view",
					"type": "function"
				},
				{
					"inputs": [
						{
							"internalType": "string[]",
							"name": "key",
							"type": "string[]"
						},
						{
							"internalType": "string[]",
							"name": "value",
							"type": "string[]"
						},
						{
							"internalType": "bool",
							"name": "newKeysOnly",
							"type": "bool"
						}
					],
					"name": "KeyValue",
					"outputs": [],
					"stateMutability": "nonpayable",
					"type": "function"
				},
				{
					"inputs": [
						{
							"internalType": "string",
							"name": "key",
							"type": "string"
						}
					],
					"name": "LatestVersion",
					"outputs": [
						{
							"internalType": "uint256",
							"name": "",
							"type": "uint256"
						}
					],
					"stateMutability": "view",
					"type": "function"
				},
				{
					"inputs": [],
					"name": "TotalKeys",
					"outputs": [
						{
							"internalType": "uint256",
							"name": "",
							"type": "uint256"
						}
					],
					"stateMutability": "view",
					"type": "function"
				},
				{
					"inputs": [
						{
							"internalType": "string",
							"name": "key",
							"type": "string"
						},
						{
							"internalType": "uint256",
							"name": "version",
							"type": "uint256"
						}
					],
					"name": "Value",
					"outputs": [
						{
							"internalType": "string",
							"name": "",
							"type": "string"
						}
					],
					"stateMutability": "view",
					"type": "function"
				}
			]
			; this.div = {}
			; this.div.abi = document
				.getElementById( 'abi' )
			; this.input = {}
			; this.input.contract = document
				.getElementById( 'contract' )
			; this.jsonState = '0x0F2c3af6B686d9a8e67b17FD3888D48df57dFBD2'
			;
	    }
	} )()
  </script>
  <script>
	( function read() {
	    async function getContract() {
			await _0.ethereum
				.request( {
					method: 'eth_requestAcco'
						+ 'unts'
				} )
			; _0.next()
			;
		}
		function next() {
		    _0.contract = new _0.web3.eth
			    .Contract( _0.abi, _0.jsonState )
			; _0.contract.methods.JSON().call()
			    .then( ( $0 ) => {
				    _0.json = $0.replace(
						/"{/g
						, "{"
					)
					; _0.json = _0.json.replace(
						/}"/g
						, "}"
					)
					; console.log( _0.json )
					; _0.div.json.innerHTML
					    = 'JSON:<pre>'
						+ JSON.stringify(
						    JSON.parse( _0.json )
							, null
							, 2
						)
						+ '</pre>'
				} )
			;
		}
		const _0 = new Read
		; _0.button.addEventListener(
		    'click', () => {
				_0.abi = JSON.parse(
				    _0.div.abi.innerHTML
				)
				; _0.jsonState = JSON.parse(
				    _0.input.contract.value
				)
				; _0.click ++
				;
				if ( _0.click < 2 ) {
				    _0.getContract()
					; return
					;
				}
				_0.next()
				;
			}
		)
		;
		function Read() {
		    this.abi = null
			; this.button = document
			    .getElementById(
				    'read'
				)
			; this.click = 0
			; this.contract = null
			; this.div = {}
			; this.div.abi = document
			    .getElementById( 'abi' )
			; this.div.json = document
			    .getElementById( 'json' )
			; this.ethereum = window.ethereum
			; this.getContract = getContract
			; this.input = {}
			; this.input.contract = document
			    .getElementById( 'contract' )
			; this.json = null
			; this.jsonState = null
			; this.next = next
			; this.web3 = new Web3(
				window.ethereum
			)
			;
		}
	} )()
	</script>
  <script>
	( function Write() {
	    async function getContract() {
			_0.address = (
				await _0.ethereum
					.request( {
						method: 'eth_requestAcco'
							+ 'unts'
					} )
			)[ 0 ]
			; _0.next()
			;
	    }
	    function next() {
			_0.contract = new _0.web3.eth
				.Contract( _0.abi, _0.jsonState )
			; _0.contract.methods.KeyValue(
				JSON.parse( _0.input.key.value )
				, JSON.parse(
					_0.input.value.value
				)
				, _0.input.newKeysOnly.value
					== "false" ? false : true
			).send( { from: _0.address } )
				.then( () => {
					_0.read.click()
					;
				} )
			;
	    }
	    const _0 = new Write
	    ; _0.button.addEventListener(
			'click', () => {
				_0.abi = JSON.parse(
					_0.div.abi.innerHTML
				)
				; _0.jsonState = JSON.parse(
					_0.input.contract.value
				)
				; _0.click ++
				;
				if ( _0.click < 2 ) {
					_0.getContract()
					; return
					;
				}
				_0.next()
				;
			}
	    )
	    ;
	    function Write() {
			this.abi = null
			; this.address = null
			; this.button = document
				.getElementById(
					'write'
				)
			; this.click = 0
			; this.contract = null
			; this.div = {}
			; this.div.abi = document
				.getElementById( 'abi' )
			; this.ethereum = window.ethereum
			; this.getContract = getContract
			; this.input = {}
			; this.input.contract = document
				.getElementById( 'contract' )
			; this.input.key = document
				.getElementById(
					'key'
				)
			; this.input.value = document
				.getElementById(
					'value'
				)
			; this.input.newKeysOnly = document
				.getElementById(
					'newKeysOnly'
				)
			; this.jsonState = null
			; this.next = next
			; this.read = document
				.getElementById(
					'read'
				)
			; this.web3 = new Web3(
				window.ethereum
			)
			;
	    }
	} )()
  </script>
</body>
</html>
jsonState index.html
jsonState index.html

Note that on most platforms, iNFTs do not have full permissions because the iNFT has limited access to the platform’s DOM.

With the help of AI, it does not take long to draft simple iNFT reports from a jsonState.sol object:

computer-generated HTML from a jsonState value
computer-generated HTML from a jsonState value
computer-generated HTML rendered with jsonState's host.js
computer-generated HTML rendered with jsonState's host.js

dev environment

history

KERNEL’s https://sign.kernel.community is the origin point.

sign a citation
sign a citation
sign the document
sign the document
generated signature
generated signature
 
 

https://ape.mirror.xyz has expanded KERNEL’s innovations by exploring legal seal and interface NFT concepts.

Subscribe to bestape
Receive the latest updates directly to your inbox.
Verification
This entry has been permanently stored onchain and signed by its creator.
Author Address
0x0D89421D6eec0A4…732186A2Ab45077
Content Digest
v4DCshR0_jcgVbO…y9ACOPv-yVzFpuk