1

I am working on a project that in which we need two contract send unpredicted amount of data to each other. those data actually are kind of structures that need to be serialized in a proper way. So we created a library named Seriality which is in charge to serialize and deserialize data and another library named BulkyChunky which is in charge to sending and receiving raw data. Seriality mostly written by Solidity assembly and it's quiet efficient to use. In fact BulkyChunky devides the serialized data buffer to a bunch of bulks in a way that one bulks contains 8 chunks and every chunks includes 32 bytes. So for getting data from your contract you need implement fetchBulk() and in which iterate over the bulks and call getBulk() function and pass the bulk number to it. By help of Seriality you can merge all of those bulk in a buffer and deserialize it base on the version of your struct.

I just wanted to share it with you guys maybe it would be useful for you too.

BulkyChunky

enter image description here

In this sample we want to send a huge amount of data from contract Callee to Caller :

Shared Schema :

pragma solidity ^0.4.16;

contract BCSchema {

struct DefinitionV1{
   uint16   version;

   address adrs;
   uint8   id;
   string  name;
   string  description;
   string  bytecode;
 } 

struct DefinitionV2{
   uint16   version;

   address adrs;
   uint8   id;
   string  name;
   string  description;
   string  bytecode;
   string  ABI;
 }
}

Contract Callee :

pragma solidity ^0.4.16;

import "./BulkyChunky.sol";
import "./BCSchema.sol";

contract Callee is BulkyChunky, BCSchema {

DefinitionV1 Definition;

function getData() public view returns (uint16 version,address adrs, uint8   id, string  name, string description, string bytecode){
    version = Definition.version;
    adrs    = Definition.adrs;
    id      = Definition.id;
    name    = Definition.name;
    bytecode= Definition.bytecode;
    description = Definition.description;
}

 function serialize() public {

    Definition.version  = 1;
    Definition.adrs     = 0xcab77b4b9bf9b92a53572091c5798c570051be8f;
    Definition.id       = 123;
    Definition.name     = new string(32);
    Definition.bytecode = new string(128);
    Definition.description = new string(128);

    Definition.name  = "BulkyChunky";

    Definition.description = "BulkyChunky is a contract aims to facilitate transffering big amount of data between the Solidity smart contracts ";

    Definition.bytecode = "0x60606040526110cc806100136000396000f30060606040526004361061008e\
                            576000357c010000000000000000000000000000000000000000000000000000";



    Buffer.size = sizeOfString(Definition.bytecode) +
                  sizeOfString(Definition.description) +
                  sizeOfString(Definition.name) +
                  sizeOfUint(16) +
                  sizeOfInt(8) + 
                  sizeOfAddress();

    if(Buffer.size % 32 > 0) 
        Buffer.size +=  (Buffer.size % 32);                     

    bytes memory buffer = new bytes (Buffer.size);

    Buffer.chunk_count = Buffer.size / 32;

    if(Buffer.size % CHUNK_BYTES_SIZE > 0 ) {
        Buffer.chunk_count++;
    }

    // Serializing
    uint offset = Buffer.size;

    uintToBytes(offset,Definition.version, buffer);
    offset -= sizeOfUint(16);

    addressToBytes(offset,Definition.adrs, buffer);
    offset -= sizeOfAddress();

    uintToBytes(offset, Definition.id, buffer);
    offset -= sizeOfInt(8); 

    stringToBytes(offset,  bytes(Definition.name), buffer);
    offset -= sizeOfString(Definition.name);

    stringToBytes(offset,  bytes(Definition.description), buffer);
    offset -= sizeOfString(Definition.description);

    stringToBytes(offset,  bytes(Definition.bytecode), buffer);
    offset -= sizeOfString(Definition.bytecode);

    Buffer.data = buffer;
} 


function deserialize() public {

}

function fetchBulk()   public {

}
}

Contract Caller :

pragma solidity ^0.4.16;

import "./BulkyChunky.sol";
import "./Callee.sol";
import "./BCSchema.sol";

contract Caller is BulkyChunky, BCSchema {

DefinitionV1 Definition;

function getData() public view returns (uint16 ,address , uint8   , string, string, string ){

    return(Definition.version, Definition.adrs, Definition.id, Definition.name, Definition.description, Definition.bytecode);
}

function createBuffere() public {

    Callee callee = Callee(0x610033b6dd5a08004e46f2097ca09b693d744118);

    callee.serialize();
    uint buffer_size = callee.getBufferSize();

    initializeBuffer(buffer_size);         
 }

function fetchBulk() public  {

    require(Buffer.size > 0);
    uint bulk_size = Buffer.size / BULK_BYTES_SIZE;
    if(Buffer.size % BULK_BYTES_SIZE > 0)
        bulk_size++;

    Callee callee = Callee(0x610033b6dd5a08004e46f2097ca09b693d744118);
    bytes memory buffer = Buffer.data;
    for(uint16 j=0 ; j < bulk_size ; j++){

        uint[BULK_CHUNK_SIZE] memory bulk = callee.getBulk(j+1);

        for(uint i = 1 ; i<= BULK_CHUNK_SIZE; i++)
           uintToBytes((i * 32) + (j * BULK_BYTES_SIZE), bulk[i-1], buffer);   
    }

   Buffer.data = buffer;
}


function deserialize() public {

    require(Buffer.size > 0);
    bytes memory buffer = Buffer.data;
    uint offset = Buffer.size;
    uint string_size;
    Definition.version = bytesToUint16(offset, buffer);
    offset -= sizeOfUint(16);

    Definition.adrs = bytesToAddress(offset, buffer);
    offset -= sizeOfAddress();

    Definition.id = bytesToUint8(offset, buffer);
    offset -= sizeOfInt(8); 

    string_size = getStringSize(offset, buffer);
    string memory name = new string(string_size);
    bytesToString(offset, buffer, bytes(name));
    offset -= sizeOfString(name);

    string_size = getStringSize(offset, buffer);
    string memory description = new string(string_size);
    bytesToString(offset, buffer, bytes(description));
    offset -= sizeOfString(description);

    string_size = getStringSize(offset, buffer);
    string memory bytecode = new string(string_size);
    bytesToString(offset, buffer, bytes(bytecode));
    offset -= sizeOfString(bytecode);

    Definition.name = name;
    Definition.description = description;
    Definition.bytecode = bytecode;
}

function serialize() public {
 }
}

OutPut :

0000000000000000000000000000000000000000000000303030303030303030 3030303030303030303030303030303030303030303030353736303030333537 6330313030303030303030303030303030303030303030202020202020202020 2020202020202020202020202020202020202020202020363030306633303036 3036303630343035323630303433363130363130303865307836303630363034 3035323631313063633830363130303133363030303339000000000000000000 00000000000000000000000000000000000000000000a07920736d6172742063 6f6e7472616374732000000000000000000000000000006f756e74206f662064 617461206265747765656e2074686520536f6c696469746f20666163696c6974 617465207472616e7366666572696e672062696720616d42756c6b794368756e 6b79206973206120636f6e74726163742061696d732074000000000000000000 000000000000000000000000000000000000000000007242756c6b794368756e 6b79000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000b7bcab77b4b9bf9b92a 53572091c5798c570051be8f0001

enter image description here

  • 2
    I suggest you have a question as a question and then your own answer below it as an answer. This would be the correct format for Q&A site like ethereum.stackexchange.com – Mikko Ohtamaa Mar 13 '18 at 8:03
  • I'm voting to close this question as off-topic because it needs to be asked and answered, where the answer includes explanations, not just a chunk of code. – eth Mar 13 '18 at 8:45