Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't remove paths from loaded node if other paths have the same prefix #40

Open
mattiaz9 opened this issue Dec 9, 2022 · 1 comment
Labels

Comments

@mattiaz9
Copy link

mattiaz9 commented Dec 9, 2022

I'm trying to manipulate a loaded mantaray node and I'm facing an issue removing paths when there are other siblings paths with the same prefix.

This is un example script:

run()

async function run() {
  batchId = await createPostageBatch()

  const data = Buffer.from("Test")

  const queue = new Queue()

  const zeroHash = new Uint8Array(64).fill(0) as Reference
  const hash = enqueueData(data, queue)
  const storageSaver = async (data: Uint8Array) => enqueueData(data, queue)
  const storageLoader = async (reference: Uint8Array) => await downloadData(reference)

  const path1 = encodePath("path1")
  const path2 = encodePath("path2")
  const path3 = encodePath("path3")

  // 1. create a node with two forks with the same content

  const node = new MantarayNode()
  node.addFork(encodePath(RootPath), zeroHash, {
    [WebsiteIndexDocumentSuffixKey]: decodePath(path1),
  })
  node.addFork(path1, hash, {
    [EntryMetadataContentTypeKey]: "text/plain",
    [EntryMetadataFilenameKey]: "test1",
  })
  node.addFork(path2, hash, {
    [EntryMetadataContentTypeKey]: "text/plain",
    [EntryMetadataFilenameKey]: "test2",
  })
  node.addFork(path3, hash, {
    [EntryMetadataContentTypeKey]: "text/plain",
    [EntryMetadataFilenameKey]: "test3",
  })
  node.removePath(path3) // <-- this works just fine

  const manifestReference = await node.save(storageSaver)

  await queue.drain()

  // test download
  const test1Resp = await fetch(
    `${Host}/bzz/${toHexString(manifestReference)}/${decodePath(path1)}`,
    {
      headers: {
        "Accept-Encoding": "identity",
      },
    }
  )
  const test2Resp = await fetch(
    `${Host}/bzz/${toHexString(manifestReference)}/${decodePath(path2)}`,
    {
      headers: {
        "Accept-Encoding": "identity",
      },
    }
  )
  const test1 = await test1Resp.text()
  const test2 = await test2Resp.text()
  console.log(`1. Path 1: '${test1}'`)
  console.log(`1. Path 2: '${test2}'`)

  // 2. Load the node from swarm and remove one of the forks

  // load mantary node
  const node2 = new MantarayNode()
  await node2.load(storageLoader, manifestReference)

  node2.removePath(path2) // <-- this fails

  const manifestReference2 = await node.save(storageSaver)

  await queue.drain()

  // test download
  const test3Resp = await fetch(
    `${Host}/bzz/${toHexString(manifestReference2)}/${decodePath(path1)}`,
    {
      headers: {
        "Accept-Encoding": "identity",
      },
    }
  )
  const test3 = await test3Resp.text()
  console.log(`2. Path 1: '${test3}'`)
}

The first removePath works but the second one, the one called after the node loading, throws the error Fork mapping is not defined in the manifest.

If I change path1, path2, path3 into something like a-path, c-path, c-path it works fine.

@bee-runner bee-runner bot added the issue label Dec 9, 2022
@mattiaz9
Copy link
Author

So, I noticed something weird about the way a node is loaded.

  1. The entry of a fork is set to be the contentAddress hence messing the the entire forks contents on a future save
  2. The forks are not recursively loaded

So I made some changes and it seems to be working fine now:

First I added a function to recursively load each forks:

private async recursiveLoad(
  storageLoader: StorageLoader,
  reference: Reference
): Promise<Reference> {
  const data = await storageLoader(reference)
  this.deserialize(data)

  if (!this.forks) return this.entry

  for (const fork in this.forks) {
    const contentAddress = this.forks[fork].node.entry
    const entry = await this.forks[fork].node.recursiveLoad(storageLoader, contentAddress)
    this.forks[fork].node.setContentAddress = contentAddress
    this.forks[fork].node.setEntry = entry
  }

  return this.entry
}

then I called that function in the load() method:

public async load(storageLoader: StorageLoader, reference: Reference): Promise<void> {
  if (!reference) throw Error("Reference is undefined at manifest load")

  await this.recursiveLoad(storageLoader, reference)

  this.setContentAddress = reference
}

Can someone confirm that the loading is buggy and not intended to be that way? because in that case I could make a pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant