...by Daniel Szego
quote
"Simplicity is the ultimate sophistication."
Leonardo da Vinci

Wednesday, January 31, 2018

Computational and business models for tokenisation


As most blockchain platforms are built on different tokens and cryptoassets it can be foreseen that most new state of the art blockchain end user applications will be based from an architectural perspective on tokens. For this reason it is an interesting question how different computational models and IT architectures can be reformulated based on tokens. Among the others:
- How accounting can be built on tokens, similarly as triple accounting ?
- How workflows can be built up with the help of tokens ? 
- How business processes can be formulated with the help of tokens ? 
- How token based collaboration models can be set ?
- How data flow models can be defined by tokens ?
- How business models can be defined with the help of tokens ?
- How organisational structure can be defined on tokens ?
- How blockchain tokens and classical database or network technology can be integrated with each other ?
- How markets can be built on tokens ?
- How AI and machine learning can be built on tokens ?
...
- What other kind of token based computational model can be imagined ?

Monday, January 29, 2018

Solidity and Truffle Tips and Tricks - all past events of a contract


So, if you want to read out all of the events of a contract and you have a geth client and a synchronized blockchain, even if you synchronized the blockchain with the --fast directive, you can use the following pattern: 

var abi = [{...}];

var contract= web3.eth.contract(abi);

var corionRef =contract.at(<... address...>);

corionRef.<Event>({},{fromBlock:0,toBlock: 'latest'}).get(
  function (error, eventResult) {
    if (error) console.log('Error in Event event handler: ' +
        error); 
    else console.log('Event result:'+ JSON.stringify(eventResult));
});





Sunday, January 28, 2018

Blockchain + smart contracts and business logic


From an architecture perspective, initial versions of a blockchain protocol, like bitcoin had a pretty simple architecture: transactions were put into the system that were validated by nodes and ordered into batches by the miners and the state transaction was computed as well in the same time. This architecture was further developed by smart contract systems like Ethereum in a way that instead of simple transactions, a complex business logic can be executed named as smart contract. 

As smart contracts seem to be a natural way to define general business logic into a blockchain system there might be a fundamentally different way of extending a blockchain architecture. Mining or ordering service is responsible for finding a subset of the transactions that are consistent and avoid double spending. However this logic can be something much more difficult, like solving different graph algorithms on the transactional graph or even general computational algorithms like something with constraint satisfaction or rule based systems. It might be even an option to define ordering based business logic as different modules that might be dynamically configured. 

In this sense business logic in a blockchain system might be designed in a two level way, similarly as in a classical software design there is client side and server side business logic:
- business logic that extends a given transaction and influences only one or just a couple of addresses should be realized as a smart contract.
- business logic that effects all of the accounts and transactions and the perhaps the ordering logic of the infrastructure as well should be realized together with the ordering service as an attachable business logic module.  


Thursday, January 25, 2018

Solidity and Truffle Tips and Tricks - using Parity with geth console on windows


Using parity with geth console on windows might be a little bit tricky. The point is to start parity with --geth option:

parity --geth

which results that the '\\.\pipe\geth.ipc' file is generated, so you can simply attach with the standard geth command:

geth attach

Wednesday, January 24, 2018

Solidity and Truffle Tips and Tricks - getting all token balances


Well, it is always a little bit problematic for a token to get a simple list on all of the accounts that have token balances at all. The problem behind is that the token balances are stored in a mapping structure which is practically a hash tree structure meaning that you can query the values for each of the individual elements but you can not iterate on the structure. So the things that you can basically do are the followings:

1. If you know the certain address or addresses, you can query the balance for these addresses with the help of the balanceOf function. Certainly there is a way to read out the total supply of a token as well with a standard function.

2. At each transfer, there is a Transfer function raised with the from and to address. Blockchain explorers can read these transfers events and query the balance of the accounts of the related addresses. 

3. If the previous point does not provide the necessary result, you can try to start scripting a taint analysis with explicitly enumerating all of the addresses that were somehow effected by the contract and query for each address explicitly the balance. 



Tuesday, January 23, 2018

On corporate and easy ICO-s


With the Hype around ICO-s the investor structure is to be found in a change. Previously only crypto fanatics were investing into the field who were technically competent to master all the challenges of the technology, like private-public key management, or dealing with the blockckahin. Nowadays, there seems to be a shift on the field with having more and more non-professional and industrial investors as well. Considering these parties, classical crypto investment technologies might not be the best fit. It is a general question if crypto investment technologies can be further developed to serve corporate ot non-professional investor groups as well.  

Saturday, January 20, 2018

Blockchain and batching


In a blockchain protocol a block is basically nothing more than a special batch which summarizes a number of transactions into one batch to provide the ability for more easy processing.  

On the different types of sharding: Lightning network, private channels vs private transactions

Lightning network at Ethereum or Bitcoin are pretty similar to the concept of private chains at Hyperledger Fabric. They simply define am off-chain channel that is hooked at the beginning and at the end to the Blockchain, but otherwise the transactions are running independently from the Blockchain, On the contrary, private transactions at Quorum can be regarded as the other side of the coin: as the transactions are running on the Blockchain, they are encrypted and only certain nodes with the necessary key are able to decrypt. The state transition of the private transactions are saved however into a special state, called private state that is separated from the private state. In this sense private channels make a splitting or sharding on the Blockchain itself as private transactions make a splitting or sharding in the state. Certainly the top is the proposed classical Ethereum sharding, in which both the state and the transaction chain are spitted into pieces.   


Figure 1, different types of sharding

Friday, January 19, 2018

Decentralized App store or DApp store


As blockchain technology slowly goes into the mainstream at least from a the marketing point if view, it might be a good question which applications are generally required for industrial scenarios. On such an application is surely something similar as a decentralized app store, which works similarly as a classical app store only for DApps. So, let we take a look which functionality should be put into such a general DApp store:

- Trusted name service: Name service should give something as a general unique, human readable name for each of the DApps. The name should be associated with a certain properties of the Dapp itself, like addresses, the ABI description files and some meta information regarding the DApp. The name service should be trusted, meaning that only people having certain private keys for the DApp should be able to update the information. It might be a further function to be able to delete certain DApp. 

- Discovery: one way for getting the information about the Apps might be simply based on the name of the DApp. However, more sophisticated discovery services can be imagined as well, like getting information based on DApp meta-information, description or even based on the ABI file.

It is certainly questionable how such a discovery can be realized in an efficient way. Further question if such a system should be blockchain specific or there is a way to realize such a functionalities in a multi or cross blockchain way.  

Tuesday, January 16, 2018

Solidity Blockchain - Metamask doesn't work with Ethereum Consortium Blockchain


If you work with Azure Blockchain especially with the different Azure Ethereum Consortium Blockchain templates and with Metamask, you can usually experience errors in several situations. Examples might vary from Metamask not able to connect to the network, or not able to receive transactions, or you can able to receive transaction but you are not able to send, because it stuck with a pending status or it freezes after one or two confirmations. The most simple resolution is to install an older version of Metamask to the browser. The most typical reason of the error is that Azure Blockchain geth nodes are still in an older release that is not compatible with the most up-to-date Metamask version. 

Sunday, January 14, 2018

Solidity and Truffle Tips and Tricks - loadScript from Truffle console


Unfortunately working with the Truffle console is sometimes pretty much limited, as an example standard geth functions as loadScript are not really defined. What you can do however is to start the truffle development environment with turffle develop and in a separate terminal start the geth with an attach command, as an example this way:

geth attach http://localhost:9545


Saturday, January 13, 2018

Solidity and Truffle Tips and Tricks - modifiers with parameters


Modifiers could have parameters as well combined for instance with the input values of a function, it is pretty cool isn't is ? As an example, the following code fragments defined a modifier that can ensure that one of the input parameters is bigger than 10. 

 modifier biggerThanTen(uint param){
   require(param > 10);
   _;
 }
    
 function test(uint _input)  biggerThanTen(_input){
   ...
 }



Solidity and Truffle Tips and Tricks - passing struct argument by reference


In solidity the structs given as parameters for a function are mostly given by value, meaning that the whole struct is practically duplicated in memory and handled as a local copy of the original struct. There is one exception that you can use if you want to use another semantics: with internal and private functions you can use the storage keyword to make sure that the struct us handled as reference and not as value. 

contract StructTestContract {
    
  struct TestStruct{
     uint a;
  }
    
  TestStruct public myStruct= TestStruct(1);
    
  function copyStructByValue(TestStruct _struct){
     _struct.a = 2;
  }

 function copyStructByReference(TestStruct storage _struct) internal{
     _struct.a = 2;
  }

 function testCopyStructByValue(){
    copyStructByValue(myStruct);
 }

 function testCopyStructByReference(){
    copyStructByReference(myStruct);
 }
}

In the previous example, copyStructByReference has got a real reference to the TestStruct resulting 2 after the function call, as copyStructByValue simply copies the whole struct meaning that the original value will not change. 

Solidity and Truffle Tips and Tricks - time in solidity


Time in solidity does not have too many options unfortunately, what you can use is basically an uint variable that represents a UNIX timestamp, that is basically the number of ticks or seconds since the 1th of January 1970. You can have the keywords now to represent the current timestamp and use the keywords like seconds, minutes, hours, days, weeks or years to add or subtract time elements. As it is demonstrated in the following code fragment:

    uint currentTime = now;
    uint nextSecond = currentTime + 1 seconds;
    uint nextMinute = currentTime + 1 minutes;
    uint nextHour = currentTime + 1 hours;
    uint nextDay = currentTime + 1 days;
    uint nextWeek = currentTime + 1 weeks;
    uint nextYear = currentTime + 1 years;



Solidity gas optimization - small int types and structs


If you use structs with integers smaller than the maximum available value, like int8, uint8, int32, uint32, you can have the chance that the solidity compiler optimizes the values into one storage element. Sometimes the storage is optimized even without an explicit struct, just with defining the small integers in a row. Taking the following code segment:

contract gasOptimisation{
    uint8 a;
    string test1;
    uint8 b;
    string test2;
    uint8 c;
    string test3;
    uint8 d;

  struct Integers{
     uint8 a;
     uint8 b;
     uint8 c;
     uint8 d;
  }    

 Integers ints;

  function setInt() {
    a = 1;
    b = 2;
    c = 3;
    d = 4;
  }

  function setStruct(){
     ints = Integers(1,2,3,4);
  }   
 }   

Running  setInt costs more than two times as much gas as running setStruct, because probably the compiler optimizes the four variables into one 32 byte word. However, if we remove the string declarations from the uint8 variables on the top of the contract, than setInt function and the storage of a,b,c,d variables are optimized as well, even without struct.      


Wednesday, January 10, 2018

Solidity and Truffle Tips and Tricks - setting up development environment with Parity



1. Install Parity: you can install parity on Ununtu or Linux with the following one line command:

 bash <(curl https://get.parity.io -kL)

2. Start development blockchain with Parity: for starting Parity development environment simply type start parity with the following parameters:

 --config dev or --chain dev for the development envrionment
 --force-ui for having a user interface
 --base-path set a base path as well, otherwise not really working for some reason.

by default, the local web environment as http://localhost:8180, you can create some new accounts, transfer ether from the development account to the others. It is an important information that the passphrase for the development account is simply an empty string. 

3. Configure Truffle with Parity: configure with the locally installed Parity environment in truffle.js as: 

networks: {
    parity: {
      host: "127.0.0.1",
      port: 8545,
      from: "0x00a329c0648769A73afAc7F9381E08FB43dBEA72",
      network_id: "*", // Match any network id
      gas: 4600000
    }
  }

It is a good idea to put some gas limit into the config file, as the parity gas limit configuration might not match with the default of Truffle.

4. Deploy with Truffle: migrate to the local parity network and test in the user interface under txqueue viewer if the transaction has been mined. Pay attention that truffle migration deploys more than one contract, so you have to sign the transaction on the graphical user interface more than once. 

 truffle migrate --network parity --verbose-vp

5. Test your contract with Parity


Ethereum token with adjustable crypto-monetary policy with group of addresses


As we have mentioned in our previous blog there is a possibility and sometimes the need as well to create a token that has a actually a monetary base and an extended money supply as well that can be achieved in the most easy way with the help of a simple multiplicator value. However in certain situations, there might be the need to have something as multiply multiplication.

So let we further refine our model, let be M0 the monetary basis and M1 = M0 * m is an extended monetary supply where m is a multiplication number. Let we define an M2 refined and extended monetary supply in a way that:

- let G={g1, g2, ... gn} a set of groups, in a way that
- for each A={a1, a2, ... ak} possible addresses, there is maximum one gi group in which the address is member
- let |G|={|g1|,|g2|, ... |gn|} the number of addresses that are associated to a given group
- besides, let we have for each group a {m1, m2, ... mk} multiplicator value.

If so, we can define the M2 refined extended monetary supply:

M2 = M1 * Sumi (|ai| * mi) / Sumi (|ai|)

It is practically a measure for creating an average of different multiplicator values weighted by the size of the groups.





   

Tuesday, January 9, 2018

Minimal ERC20 token with adjustable monetary policy


As we have seen in the previous blog (Ethereum token with adjustable monetary policy), there might be a good idea to design a token with adjustable monetary supply, in a way that there is actually at least two token balances an M0 basic monetary supply and an M1 that is a dynamic multiplication of the basic monetary supply. The following code demonstrates a minimal implementation of such a token. For the first run as a simple sketch, without having some necessary elements for a live system, like Transfer event, safe match functions or token information fields 

contract SimpleMonetaryToken {

 mapping(address => uint256) m0Balances;
 uint256 public monetaryMultiplicator = 110;

 uint initialSupply = 10000;

 function SimpleMonetaryToken(){
  m0Balances[msg.sender] = initialSupply;
 }

 function transfer(address _to, uint256 _m1Value) public returns
      (bool) {
  uint256 _m0Value = (_m1Value * 100) / monetaryMultiplicator;
  require(_to != address(0));
  require(_m0Value <= m0Balances[msg.sender]);

  m0Balances[msg.sender] = m0Balances[msg.sender] - _m0Value;
  m0Balances[_to] = m0Balances[_to] + _m0Value;
  return true;
  }

 function balanceOf(address _owner) public view returns (uint256
  balance) {
   return (m0Balances[_owner] * monetaryMultiplicator) / 100;
 }

Certainly, the structure should be further tested regarding the possible hackings or attacks. As an example division represents actually a rounding, so it might produces some inconsistencies or possible hackings. On the other hand, due to multiplications with 100, the overflow can be a critical issue.






Sunday, January 7, 2018

Ethereum token with adjustable crypto-monetary policy


To realize tokens with adjustable monetary policy is actually pretty much a challenge. One way of doing it is to create something like a mintable token that has an explicit function called mint that is able to create new tokens on a certain account. However this structure actually does serve well in certain use cases, like:
- if the newly generated tokens should be distributed somehow to all of the possible accounts
- if the monetary supply is not only to be increased but, we should be able to decreased as well.

In such situations, perhaps another algorithm might be feasible, that has the analogy in the classical banking systems. Let we imagine as a simple situation that we have actually two monetary basis, M0 is practically the amount of cash in the system and M1 is the amount of electronic money in the system. In the most simple situation, M1 is based on the reserve rates of the banks that is identified by the central banks, so simply put: 

M1 = m * M0, where m is a multiplication factor  

Having this structure, tokens might be built up directly that captures this functionality in a direct way:
- balance: balance as an internal mapping would always store the M0 value, however a balance function can be derived that gives the M1 value back. 
- transfer: transfer should always be regarded to the M1 value, based on the current m multiplication factor, balance M0 balance should be as M1/m adjusted. 

Certainly, it a pretty good question how such a token could work from an end-user perspective. As certainly, having more token on the balance is pretty nice to have, having less is probably not really accepted. On the other hand, people might explicitly distinguish between M0 and M1 balance, which might cause some less welcoming economic behaviors, like spending more if the m value is high, but spending less if it is low. 





Solidity and Truffle Tips and Tricks - unit tests and states


Truffle initializes new the state of the smart contracts (or deploys them new) both at the beginning of the testing and at each contract keywords. This practically means each new test starts from the state that is initialized by the migration script. From a practical point of view the following statement means a complete new initialisation or deployment:

contract('Contract', function(accounts) {
...

Solidity and Truffle Tips and Tricks - unit test from a different account


Supposing you want to carry out a unit test from a specific account that is different as the default account, you can basically use the accounts array that is initialized by the truffle development environment and you can explicitly set a specific account as accounts[i] at the function call:

contract('Contract', function(accounts) {
 it("test Contract other account", function() {
  return Contract.deployed().then(function(instance) {
   return Contract.callFunction( <parameters> {from:accounts[i]});  
   }).then( 
...
...

Solidity and Truffle Tips and Tricks - testing errors as unit tests


Supposing that you have to write a solidity unit test and you expect the result as an error message, you can use the following pattern, simply using catch in the unit testing instead of or beside then

contract('Contract', function(accounts) {
 it("test Contract from wrong account", function() {
  return Contract.deployed().then(function(instance) {
   return Contract.callFunction(<params>); 
  }).then(function(balance) {
   assert(false, "Call should not be allowed");            
  }).catch(function(error) {
   errorMessage = error.toString();
   if (errorMessage.indexOf("invalid opcode")  > 0){
    assert(true, "Call should not be allowed - error as expected");     }
    else{
   assert(true, "Call should not be allowed - wrong message");   
    }
   });
  });
});

Saturday, January 6, 2018

Solidity and Truffle Tips and Tricks - testing events in unit tests


Supposing you want to check if an event has been raised during a unit test, you can simply use parts of the result variable. As an example result.logs[0].event shows the name of the raised event. 

 return Contract.functionCall(<parameters>);             
        }).then(function(result) {
            event = result.logs[0].event;
    assert.equal(event, "EventName", "Event raised"); 

Thursday, January 4, 2018

Solidity and Truffle Tips and Tricks - Invalid number of arguments in web3,js


If you work with solidity and truffle and you get the following error message form web3.js :

Invalid number of arguments to Solidity function

It can be resulted because something has gone corrupted in the build folder during the last build process. So simply delete the build folder and run:

truffle migrate --reset --compile-all

Solidity and Truffle Tips and Tricks - Ganache on Ubuntu


Ganache seems to a cool tool from Truffle for realizing a test rpc. However, it is still somehow at the beginning phase of the development. Sometimes it is not so trivial to set up, and sometimes not so sure how it will be integrated with the current test rpc from Truffle. 

Anyway if you want install on Ubuntu, use the following procedure:

git clone https://github.com/trufflesuite/ganache

run npm install

run npm start

Having deployed, make sure that the truffle.js file contains the correct host and port information, by default and configure truffle with same parameters as well.

host: 127.0.0.1
port: 7545 

If you want to use geth console on the top of ganache, you can simply run it from a different terminal:

geth attach http://localhost:7545



Tuesday, January 2, 2018

Solidity and Truffle Tips and Tricks - Overflows and safe arithmetic


One of the problem is with the solidity language that overflow or underflow of an integer value is not really checked at the moment. As a result, providing wrong values by chance or at a hacking attack can very easily cause unexpected behavior. As an example, considering the following function: 

    function add(uint8 _a, uint8 _b) returns (uint8) {
        return _a + _b;
    }

As add(100,10) result in 110 as expected add(255,10) results in 9 which is not surely intended as a result. If in such a situation, it is rather expected that an error is thrown indicating overflow, than for instance the following safe add function can be used:

    function addSafe(uint8 _a, uint8 _b) returns (uint8) {
        assert((_a + _b >= _a) && (_a + _b >= _b));
        return _a + _b;
    }  






Solidity and Truffle Tips and Tricks - Debug and log pattern


Solidity contracts are not really debuggable, even if you can use the minimum debugging functionality from Truffle, there is the place for a lot of improvement. The situation can be more critical if you have to debug your source code in the production environment, which is happen to be almost impossible. One way might be to have an explicit pattern that is capable to log information during execution. An example implementation can be seen bellow. The Loggable ancestor class provides the logging functionality that can be turned on or off by an administrator even in production.

Several problems exist though with this simple design that might be fine tuned in the future: 

1. The events can be only defined as public as a consequence nothing prevents in the descendant class calling directly the LogEvent instead of the Log function. It is possible something that can not better designed in the future, so it must be explicitly  paid attention that the Log function is called.

2. The logging event must be as cheap as possible from a gas consumption perspective. Current implementation cost about 600 gas if the logging turned off and 2500 if it is turned on. However with more logging logic this might be further improved.         

3. This logging is absolutely open for everyone to see, which is might not be a good idea on a public network in a production scenario. It is a general further question how secure logging with minimal gas overhead can be realized.  

contract Loggable
{
    bool public debug;
    address admin; 
    
    event LogEvent(string info);
    
    modifier isAdmin{
        require(msg.sender == admin);
        _;
    }
    
    function Loggable(){
        admin = msg.sender;
    }
    
    function setDebug(bool _debug) isAdmin public{
        debug = _debug;
    }
    
    function Log(string message) public{
        if (debug){
            LogEvent(message);
        }
    }    
}

contract Test is Loggable{
    
    function Test() public{
        Log("Test");
    }
}

Monday, January 1, 2018

Genetic and evolution algorithms and market


The blockchain application called cryptokitties provides some interesting ideas about genetic and evolution algorithms and the market. In classical evolution and genetic algorithms there is usually a target or fitness function to evaluate a certain population or individual and the goal is to minimize the difference between target value and the actual performance of the population. However the whole concept might be put into a market context. The mutated or combined entities of the population are exchanged or traded between different actors. As the time goes on, high value individuals are traded frequently or for a high price as less important individuals will have low liquidity and low price. Certainly, in this way the target value that is evaluated in each round depends on the subjective evaluation of the individuals taking part in the trade. As these subjective preferences might evolve over the time, it is pretty questionable in which direction does the algorithm converge.

Solidity gas optimization - creating child contract versus child struct


Solidity provides the way to create a new contract from an existing one with the help of the new keyword. It is important to note however that contract creation is one of the most expensive operation in solidity. If the use-case allows however you can simply use a struct instead if subcontracts. Certainly it must be payed attention how the functions are realized that should be associated with the child contract. In the bellow example creating the contracts with ContractFactory requires at least 4 times as much gas as creating almost the same functionality with StructFactory.    

contract SubContract{
    int subVariable;
    
    function SubContract(int _initValue){
        subVariable = _initValue;
    }
}

contract ContractFactory{
    SubContract [] subContract;
    
    function generate(){
        for (int i = 0; i < 10; i++) {
        SubContract newContract = new SubContract(i);  
        subContract.push(newContract);
        }
    }
}

contract StructFactory{
    
    struct SubStruct {
        int subVariable;
    }
    
    SubStruct [] subStruct;
    
    function generate(){
        for (int i = 0; i < 10; i++) {
        SubStruct memory newStruct = SubStruct(i);  
        subStruct.push(newStruct);
        }
    }
}

Solidity gas optimization - storage and local variables of basic types


If you have function that does some local computation, try to use access to the global poperties or variables of the contract as rarely as possible. Global variables of a contract represent always storage, so setting the variable relative often result in an enormous gas cost. On the contrary, local variables of basic types are stored in the stack so accessing them does not cost gas. In the following example testMemory has a couple of hundreds of gas cost, but testStorage a couple of hundred thousands. 

contract testContract
{
    int public storageInt = 0;
    
    function testMemory(){
        int j;
        for (int i = 0; i < 100; i ++){
            j++;
        }
    }

    function testStorage(){
        int j;
        for (int i = 0; i < 100; i ++){
            storageInt++;
        }
    }
}

Solidity gas optimization - memory arrays


Whenever, you have to make some internal computation in a solidity function with the help of an array, try to use memory arrays instead of storage. By default creating an array means storage location however if you know exactly the size of the array and you do not want to use "push" operator, you can use fixed size memory arrays.

function testStorage(){
    uint[100] i;
    i[1] = 1;
    i[2] = 2;
    i[3] = 3;
}

function testMemory(){
    uint[100] memory i;
    i[1] = 1;
    i[2] = 2;
    i[3] = 3;

As in "testStorage" each new value adding associated to the array cost about 20.000 gas, in the "testMemory" example accessing the values of the array practically does not cost anything.

Solidity and Truffle Tips and Tricks - iteration on a mapping


Mapping is a great structure in solidity, however a big drawback is to make an iteration on that. Basically it is not really possible, what you can do are the followings: 

1. If the key-space is small like working with uint8, you can iterate the whole key-space.
2.  You can use a pattern that adds the used key into an array as well, like bellow. Certainly this pattern increases the gas consumption.  

contract Iterrativemapping  {
  mapping(keyType = valueType) myMapping;
  keyType[] possibleKeys;

  function insert (keyType key, valuType value) public {
    possibleKeys.push(key);
    myMapping[key] = value;
  }
  
  function remove ....

  function setValue ...

}

3. Last but not least, you can create an event that is triggered at setting the value. Certainly this scenario does not provide a way to iterate on the mapping from a solidity contract, but there will be an off-chain log available about possible keys, values and about the whole history that can be evaluated off-chain.

contract Mappingwithevent {
  mapping(keyType = valueType) myMapping;

  event ValueSetEvent(keyType, valueType);

  function setValue (keyType key, valuType value) public {
    myMapping[key] = value;
    ValueSetEvent(key, value);
  }
  
}