[Ethereum] read error unexpected EOF

contract-developmentquorumweb3js

I'm working a evidence application with quorum.I want to store the entire contents of a file on my private blockchain. Although it's not recommended. At first I use a linux command 'split' cut a big file into some smaller tiles witch size limit to 10KB,then encode every tile content into my contract abi parameters and send the tx to rpc server.My test contract code is as below:

contract fileCtxEvidence{
    enum EviState { FINISHED,START_MOD,WAIT_OTHER_SIG,CANCEL_MOD,WAIT_LEFT_TILES }
    uint caseId;
    struct FileEvi{
        string fileName;
        bytes fileCtx;
        uint upTime;
        address upOperator;
        EviState state;
    }
    mapping(string => FileEvi) evi;
    event SaveEvi(address _oper,uint _time,string _name,uint _flag);
    constructor (uint _id) public{
        caseId = _id;
    }
    function saveFileEvi(string _name,bytes _file,uint _upTime ) public{
            evi[_name].fileName = _name;
            evi[_name].upTime = _upTime;
            evi[_name].upOperator = tx.origin;
            evi[_name].fileCtx = _file;            
           emit SaveEvi(tx.origin,_upTime,_name,0);


    }
    function getFileEvi(string _name) public view returns(bytes _file,uint _upTime,address _upOperator) {
        _file = evi[_name].fileCtx;
        _upTime = evi[_name].upTime;
        _upOperator = evi[_name].upOperator;
    }
}

My web js code is as below:

for (var i = 0;i < tilesLen;i++){
       var tileName = dirData[i];
       var tilePath = 'ctx-uploads/'+fileName+"/"+tileName;
       const readStream = fs.createReadStream(tilePath);
       let data = '';
       readStream.setEncoding('binary')
       readStream.once('error', err => {
            return cb(err)
       })
       readStream.on('data', chunk => (data += chunk))
       readStream.on('end', () => {
          var buf =  Buffer.from(data, 'binary');
          var ctx = '0x' + buf.toString('hex');
          //saveEvidenceTile(fileName,ctx,privateKey,res);
         var eviTime = new Date().getTime();
         var encodeAbi = eviContract.methods.saveFileEvi(fileName,fileCtx,eviTime).encodeABI();
         //send signed tx by sendSignedTransaction
         ......
       });
    }

But I got the "read error unexpected EOF" error on the quorum console.I traced the code and found the error is reported from function Receve in the file:vendor/golang.org/x/net/websocket/websocket.go.Since I used the websocket to connect the rpc sever.The code is as below:

func (cd Codec) Receive(ws *Conn, v interface{}) (err error) {
    ws.rio.Lock()
    defer ws.rio.Unlock()
    if ws.frameReader != nil {
        _, err = io.Copy(ioutil.Discard, ws.frameReader)
        if err != nil {
            return err
        }
        ws.frameReader = nil
    }
again:
    frame, err := ws.frameReaderFactory.NewFrameReader()
    if err != nil {
        return err
    }
    frame, err = ws.frameHandler.HandleFrame(frame)
    if err != nil {
        return err
    }
    if frame == nil {
        goto again
    }
    maxPayloadBytes := ws.MaxPayloadBytes
    if maxPayloadBytes == 0 {
        maxPayloadBytes = DefaultMaxPayloadBytes
    }
    log.Error(fmt.Sprintf("maxPayloadBytes = %d\n",maxPayloadBytes));
    if hf, ok := frame.(*hybiFrameReader); ok && hf.header.Length > int64(maxPayloadBytes) {
        // payload size exceeds limit, no need to call Unmarshal
        //
        // set frameReader to current oversized frame so that
        // the next call to this function can drain leftover
        // data before processing the next frame
        ws.frameReader = frame
        return ErrFrameTooLarge
    }
    payloadType := frame.PayloadType()
    data, err := ioutil.ReadAll(frame)
    if err != nil {
        return err
    }
    return cd.Unmarshal(data, payloadType, v)
}

And Unmarshal defined as below:

var websocketJSONCodec = websocket.Codec{
    // Marshal is the stock JSON marshaller used by the websocket library too.
    Marshal: func(v interface{}) ([]byte, byte, error) {
        msg, err := json.Marshal(v)
        return msg, websocket.TextFrame, err
    },
    // Unmarshal is a specialized unmarshaller to properly convert numbers.
    Unmarshal: func(msg []byte, payloadType byte, v interface{}) error {
        dec := json.NewDecoder(bytes.NewReader(msg))
        dec.UseNumber()

        return dec.Decode(v)
    },
}

The finally error is threw from the Unmarshal function. It used golang's json packet to decode the incoming message.When I changed the tiles size to less then 7KB and it works fine.
I checked the maxRequestContentLength is 1024 * 512.So I think quorum would receive less than 512K size message.Why the result shows that it can only receive 7KB data?
I don't know if there is any size limit on the websocket buffer or golang json decode buffer.
Any suggestion will be appreciative!

Best Answer

If you are using go-ethereum to interact with your smart contract via websockets, make sure you are using at least version 1.9.1 of go-ethereum.

Recently, go-ethereum changed the underlying websocket implementation from golang.org/x/net/websocket to github.com/gorilla/websocket.

In my case, after updating go-ethereum with go get -u github.com/ethereum/go-ethereum, the "unexpected EOF" error disappeared when sending transactions with big payloads to smart contracts deployed on Ganache.

Related Topic