ethereumjs / merkle-patricia-tree

Project is in active development and has been moved to the EthereumJS VM monorepo.

Home Page:https://github.com/ethereumjs/ethereumjs-monorepo

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Data gets lost when using string as a key. (memdown + 2 tries)

charlielye opened this issue · comments

The test below fails. If you comment line 50 with key thisbreaks the test passes. Changing the key to a Buffer and the test passes. I'm not confident that the pass is a fix, but is possibly just an intermittent fix, as I've been experiencing other oddities.

const levelup = require('levelup');
const memdown = require('memdown');
const MerklePatriciaTree = require('merkle-patricia-tree');

class Trie {
  constructor(db) {
    this.trie = new MerklePatriciaTree(db);
  }

  async get(key) {
    return new Promise((resolve, reject) => {
      this.trie.get(key, (err, value) => {
        if (err) {
          return reject(err);
        } else {
          return resolve(value);
        }
      });
    });
  }

  async put(key, value) {
    return new Promise((resolve, reject) =>
      this.trie.put(key, value, err => {
        if (err) {
          return reject(err);
        } else {
          return resolve();
        }
      }),
    );
  }
}

describe('trie', () => {
  it('minimum test that breaks', async () => {
    const db = levelup(memdown());

    const trie1 = new Trie(db);
    const trie2 = new Trie(db);

    const key1 = Buffer.from('ffffff', 'hex');
    const val1 = Buffer.from('afafaf', 'hex');
    await trie1.put(key1, val1);

    const key2 = Buffer.from('ababab', 'hex');
    const val2 = Buffer.from('deadbeef', 'hex');
    await trie2.put(key2, val2);

    await db.put('thisbreaks', Buffer.from('bdbdbd', 'hex'));

    const result1 = await trie1.get(key1);
    const result2 = await trie2.get(key2);

    expect(result1).toEqual(val1);
    expect(result2).toEqual(val2);
  });
});

For reference, see also discussion on Gitter here.

I suspect somehow putting the string changes default serialization of the db object. If the line is modified to: await db.put('thisbreaks', Buffer.from('bdbdbd', 'hex'), { keyEncoding: 'binary', valueEncoding: 'binary' });, or key is provided as a Buffer (as you mentioned) the test passes.

However this part of the library is under change, please see #74. After the changes are released, a DB instance should be provided to Trie which enforces the binary encoding and should hopefully fix this. Additionally, it throws if the parameters are not Buffer, hopefully preventing these type of errors.

API has been updated on v4 to only accept buffers so should not be an issue any more, will close.