0

I'm trying to add a simple string and store it in the Ethereum database as a key-value pair. (ID as key and a string as value)

What would be the best way to do that? I have setup multiple geth Ethereum nodes in my lab. I was thinking of writing a solidity contract that does the following -

  1. Function for adding entry (id and string), which stores this key-value pair in the internal leveldb.
  2. Getting a string value - given an id, which looks up the id (key) in the database and returns the value.

However, I am not able to find the appropriate function calls or API's that can help accomplish this. If there is an alternate approach that may be helpful, pls let me know.

Thanks!

  • Have you tried using mapping? – R.D Oct 9 '18 at 10:35
  • 1
    @R.D - Yes - that's what I am gonna use. My earlier understanding was that mappings are a temporary data store. From further posts, I understand, this can be used to write the data to the actual blockchain itself. – techieChamp Oct 10 '18 at 7:16
1

Geth Ethereum clients use leveldb to store the Ethereum blockchain (global state), however Ethereum by design provides some sort of API over JSON-RPC called ABI (Application Binary Interface) to send transactions and query smart contracts. So you don't have to worry about which database is used by the client, you only need to know the ABI that will help you to define your transaction or query.

I really recommend you to read the Solidity documentation to understand Ethereum, Smart contract and state and integration.

The web3js library helps to integrate a client application with a smart contract:

  1. Write a smart contract that store a value

code sample:

pragma solidity ^0.4.20;

contract ValueStorage {

    ////////////////////////////////////////////////////
    // Storage      
    // This represent my state I want to store on Ethereum world computer
    uint value;
    ////////////////////////////////////////////////////


    ////////////////////////////////////////////////////
    // Transacion      
    // This is a function that changes the state and require a transaction
    function setValue(uint _value) public {
        value = _value;
    }
    ////////////////////////////////////////////////////


    ////////////////////////////////////////////////////
    // Call      
    // This is a function that read the state and doesn't require a transaction
    function getValue() public view returns  (uint) {
        return value; 
    }
    ////////////////////////////////////////////////////
}
  1. Using for example a nodejs to deploy and interact with the smart contract

code sample:

(async () => {

    const Web3 = require('web3');
    const solc = require('solc')

    // Connect to the node
    var web3 = new Web3();
    web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));

    // Smart contract source
    let source = "pragma solidity ^0.4.20;" +
    "contract ValueStorage {" +
    "   uint value;" +
    "   function setValue(uint _value) public {" +
    "       value = _value;" +
    "   }" +
    "   function getValue() public view returns  (uint) {" +
    "       return value; " +
    "   }" +
    "}";

    // Deploy the contract
    let instance = await deployContract(web3, source);

    ///////////////////
    // Send a transaction to set he value to 10
    await setValue(instance, 10);

    // Query the contract to get the value
    let value1 = await getValue(instance);
    console.log("value="+value1);

    ///////////////////
    // Send a transaction to set he value to 15
    await setValue(instance, 15);

    // Query the contract to get the value
    let value2 = await getValue(instance);
    console.log("value="+value2);

    ///////////////////

    async function deployContract (web3, source) {

        return new Promise( (resolve, reject) => {

            let compiledContract = solc.compile(source, 1);
            let abi = compiledContract.contracts[':ValueStorage'].interface;
            let bytecode = compiledContract.contracts[':ValueStorage'].bytecode;

            let gasEstimate = web3.eth.estimateGas({data: bytecode});
            let ValueStorageContract = web3.eth.contract(JSON.parse(abi));

            ValueStorageContract.new({from: web3.eth.coinbase, data:bytecode, gas:gasEstimate}, function(err, contract) {
               if(!err) {
                  if(!contract.address) {
                      console.log("Transaction Hash=" + contract.transactionHash) // The hash of the transaction, which deploys the contract
                  } else {
                      console.log("Contract Address=" + contract.address) // the contract address
                      resolve(contract);
                  }
               } else {
                   console.err(err);
                   reject(err);
               }
            });

        });
    }


    async function setValue (instance, value) {

        return new Promise( (resolve, reject) => {

            instance.setValue.sendTransaction(value, {from: web3.eth.coinbase}, function(err, tx) {
               if(!err) {
                    console.log("Transaction Hash=" + tx) // The hash of the transaction, which set the value
                    resolve();
               } else {
                   console.err(err);
                   reject(err);
               }
            });

        });
    }

    async function getValue (instance) {

        return new Promise( (resolve, reject) => {

            instance.getValue.call(function(err, value) {
               if(!err) {
                    resolve(value);
               } else {
                   console.err(err);
                   reject(err);
               }
            });

        });
    }

})();

I pushed on GitHb the code here and see the result

$ node index.js 
Transaction Hash=0xfe9b36d2c6654b430812f200fa8665b287b686a7835a0a0a97039cbb5ea67ca0
Contract Address=0xc54eb03b03d8c59ff662f4c9a26961fc15d85e14

Transaction Hash=0xe8cd48896b814ffd0b7e55a6d6548bae6bbe2c785175cdbdd4813b38514d1c57
value=10

Transaction Hash=0xd8706fbe83d29fff2c382fcaa8d00cf15344c484ae55dc4de4c2351eb9e1ffd1
value=15
  • Thanks for the response Greg. I am familiar with how to write a solidity contract. So, from your post above, it looks like when I define a member variable in a solidity contract, that gets stored in leveldb or whatever db the Ethereum node has. Please confirm if my understanding is correct. – techieChamp Oct 9 '18 at 12:24
  • However, this would not be a persistent storage. I guess, there may be a way to make this persistent. Let me check. – techieChamp Oct 9 '18 at 12:26
  • 1
    A storage field like 'value' is defined in the smart contract is persistent and immutable. – Greg Jeanmart Oct 9 '18 at 12:29
  • A blockchain is an append-only distributed database replicated across every nodes of the network. Each new transaction (transfer of value or smart contract transaction) is added in a block by a node and shared to the other nodes. It means, at each block, from any node, you can rebuild a global state (account balance and smart contract storage fields) based on the previous blocks and transactions A client using a database like LevelDB just organize all the blocks and transactions in an efficient way to store new block and expose any state data. – Greg Jeanmart Oct 9 '18 at 12:41
  • so, let me clarify - Ethereum uses some data structure to store data it just added in its block as well as data from all other nodes. So, if this one node goes down, it still recovers the data from other nodes. However, does this mean there is still a possibility in a private network in particular, that the entire network may go down if all nodes are in one place? – techieChamp Oct 9 '18 at 14:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.