2

What I have so far

I have a Validator contract that is supposed to insert a key-value pair in the database contingently on a particular invariant being satisfied.

contract Validator
{
   DataBase dataBase;
   Aggregator aggregator;

   function Validator(
       DataBase _database,
       Aggregator _aggregator
   )
   {
      database = _database;
      aggregator = _aggregator;
   }

   function insert(uint key, uint value)
   {
     dataBase.insert(key, value);
     assert(aggregator.ComplexFunction() > 0);
   }
}

I have a contract Aggregator (with various internal functions used as subroutines) which computes a complex function that necessitates informations from the DataBase and from an ExtraInfoProvider (which is a preexisting contract that I did not write).

contract Aggregator
    {
        DataBase database;
        ExtraInfoProvider extraInfoProvider;

        function Aggregator(DataBase _database, ExtraInfoProvider _extrainfoProvider)
        {
           database = _database;
           extraInfoProvider = _extraInfoProvider;
        }

        function ComplexFunction()
        {
          // Compute complex function which involves iterating over
          // all of the key-value pair in the database and consulting 
          // the ExtraInfoProvider

        }
    }

Finally I have a DataBase which supports iterating over the keys: note the use of getKeyCount and getKey to get around the impossibility of returning dynamically sized array in Solidity; (experienced solidity programmers are probably very familiar with this)

contract DataBase
{
    function getKeyCount() returns (uint keyCount);

    function getKey(uint index) returns (uint key);

    function get(uint key) returns value;

    function insert(key, value)
}

The problem with this organization is the complex nesting between the classes, which is reflected by the impossibility of creating clean unit-tests.

I would like to be able to create a MockDataBase and a MockAggregator in order to be able to cleanly UnitTest my Validator class without having to pass an instance of MockDataBase to the MockAggregator

What I would like to have

In an ideal world where Solidity supports passing dynamic arrays AND structures between contracts you could do something as follow:

struct KeyValuePair
{
    uint key;
    uint value;
}

contract Validator
{
   DataBase dataBase;
   Aggregator aggregator;

   function Validator(
      DataBase _database,
      Aggregator _aggregator
   )
   {
      database = _database;
      aggregator = _aggregator;
   }

   function insert(uint key, uint value)
   {
     dataBase.insert(key, value);

     KeyValuePair[] pairs = database.getAllKeyValuePairs();
     assert(aggregator.ComplexFunction(pairs) > 0);
   }
}

This would allow me to cleanly mock the Aggregator and the Database.

How could I achieve this result given the constraint present in Solidity?

(I could collect keys and values and create 2 dynamic arrays in the Validator and pass them to the Aggregator, but I do not like the idea of passing two arrays which are supposed to by in sync).

This is not entirely about testing

I don't intend to start an argument between Classicists and UnitTester: I perform both UnitTest and organic tests with real objects on my contracts. This is not entirely about testing: I am concerned about the pattern above as a general code smell.

I don't like the necessity for synchronization between the Aggregator and the Database: for example, if I want to augment my system to allow contracts upgrades, it would be way easier to substitute my Aggregator and my DataBase independently if they did not have mutual dependencies.

Your Answer

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

Browse other questions tagged or ask your own question.