-
Notifications
You must be signed in to change notification settings - Fork 4
chore(PE-8643): hb patch system for primary names #438
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
Changes from 5 commits
57ad48b
f06ae20
2692e25
3619567
9876f91
c820c3e
78d1da0
8082bad
5e79506
b61b317
d18cf6e
e6099b6
04b611b
627b426
e8c79e8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,4 +38,96 @@ function hb.patchBalances(oldBalances) | |
| return affectedBalancesAddresses | ||
| end | ||
|
|
||
| ---@return PrimaryNames|nil affectedPrimaryNamesAddresses | ||
| function hb.createPrimaryNamesPatch() | ||
| ---@type PrimaryNames | ||
arielmelendez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| local affectedPrimaryNamesAddresses = { | ||
| names = {}, | ||
| owners = {}, | ||
| requests = {}, | ||
| } | ||
|
|
||
| -- if no changes, return early. This will allow downstream code to not send the patch state for this key ('primary-names') | ||
| if | ||
| next(_G.HyperbeamSync.primaryNames.names) == nil | ||
| and next(_G.HyperbeamSync.primaryNames.owners) == nil | ||
| and next(_G.HyperbeamSync.primaryNames.requests) == nil | ||
| then | ||
| return nil | ||
| end | ||
|
|
||
| -- build the affected primary names addresses table for the patch message | ||
| for name, _ in pairs(_G.HyperbeamSync.primaryNames.names) do | ||
| -- we need to send an empty string to remove the name | ||
| affectedPrimaryNamesAddresses.names[name] = PrimaryNames.names[name] or "" | ||
| end | ||
| for owner, _ in pairs(_G.HyperbeamSync.primaryNames.owners) do | ||
| -- we need to send an empty table to remove the owner primary name data | ||
| affectedPrimaryNamesAddresses.owners[owner] = PrimaryNames.owners[owner] or {} | ||
| end | ||
| for address, _ in pairs(_G.HyperbeamSync.primaryNames.requests) do | ||
| -- we need to send an empty table to remove the request | ||
| affectedPrimaryNamesAddresses.requests[address] = PrimaryNames.requests[address] or {} | ||
| end | ||
|
|
||
| if next(PrimaryNames.names) == nil then | ||
arielmelendez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| affectedPrimaryNamesAddresses.names = {} | ||
| elseif next(affectedPrimaryNamesAddresses.names) == nil then | ||
| affectedPrimaryNamesAddresses.names = nil | ||
arielmelendez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| end | ||
|
|
||
| if next(PrimaryNames.owners) == nil then | ||
arielmelendez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| affectedPrimaryNamesAddresses.owners = {} | ||
| elseif next(affectedPrimaryNamesAddresses.owners) == nil then | ||
| affectedPrimaryNamesAddresses.owners = nil | ||
| end | ||
|
|
||
| if next(PrimaryNames.requests) == nil then | ||
| affectedPrimaryNamesAddresses.requests = {} | ||
| elseif next(affectedPrimaryNamesAddresses.requests) == nil then | ||
| affectedPrimaryNamesAddresses.requests = nil | ||
| end | ||
|
|
||
| -- if we're not sending any data, return nil which will allow downstream code to not send the patch message | ||
| if next(affectedPrimaryNamesAddresses) == nil then | ||
| return nil | ||
| end | ||
|
|
||
| return affectedPrimaryNamesAddresses | ||
| end | ||
|
|
||
| function hb.resetHyperbeamSync() | ||
| HyperbeamSync = { | ||
| balances = {}, | ||
|
||
| primaryNames = { | ||
| names = {}, | ||
| owners = {}, | ||
| requests = {}, | ||
| }, | ||
| } | ||
| end | ||
|
|
||
| --[[ | ||
| 1. Create the data patches | ||
| 2. Send the patch message if there are any data patches | ||
| 3. Reset the hyperbeam sync | ||
| ]] | ||
| function hb.patchHyperbeamState() | ||
| local patchMessageFields = {} | ||
|
|
||
| -- Only add patches that have data | ||
| local primaryNamesPatch = hb.createPrimaryNamesPatch() | ||
| if primaryNamesPatch then | ||
| patchMessageFields["primary-names"] = primaryNamesPatch | ||
| end | ||
|
|
||
| --- Send patch message if there are any patches | ||
| if next(patchMessageFields) ~= nil then | ||
| patchMessageFields.device = "[email protected]" | ||
| ao.send(patchMessageFields) | ||
| end | ||
|
|
||
| hb.resetHyperbeamSync() | ||
| end | ||
|
|
||
| return hb | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -146,6 +146,8 @@ function primaryNames.createPrimaryNameRequest(name, initiator, timestamp, msgId | |
| else | ||
| -- otherwise store the request for asynchronous approval | ||
| PrimaryNames.requests[initiator] = request | ||
| -- track the changes in the hyperbeam sync | ||
| HyperbeamSync.primaryNames.requests[initiator] = true | ||
| primaryNames.scheduleNextPrimaryNamesPruning(request.endTimestamp) | ||
| end | ||
|
|
||
|
|
@@ -205,6 +207,7 @@ function primaryNames.approvePrimaryNameRequest(recipient, name, from, timestamp | |
|
|
||
| -- set the primary name | ||
| local newPrimaryName = primaryNames.setPrimaryNameFromRequest(recipient, request, timestamp) | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: stray whitespace. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| return { | ||
| newPrimaryName = newPrimaryName, | ||
| request = request, | ||
|
|
@@ -228,6 +231,12 @@ function primaryNames.setPrimaryNameFromRequest(recipient, request, startTimesta | |
| startTimestamp = startTimestamp, | ||
| } | ||
| PrimaryNames.requests[recipient] = nil | ||
|
|
||
| -- track the changes in the hyperbeam sync | ||
| HyperbeamSync.primaryNames.names[request.name] = true | ||
| HyperbeamSync.primaryNames.owners[recipient] = true | ||
| HyperbeamSync.primaryNames.requests[recipient] = true | ||
|
|
||
| return { | ||
| name = request.name, | ||
| owner = recipient, | ||
|
|
@@ -247,6 +256,10 @@ function primaryNames.removePrimaryNames(names, from) | |
| local removedPrimaryNamesAndOwners = {} | ||
| for _, name in pairs(names) do | ||
| local removedPrimaryNameAndOwner = primaryNames.removePrimaryName(name, from) | ||
| -- track the changes in the hyperbeam sync | ||
| HyperbeamSync.primaryNames.names[name] = true | ||
| HyperbeamSync.primaryNames.owners[from] = true | ||
|
|
||
atticusofsparta marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| table.insert(removedPrimaryNamesAndOwners, removedPrimaryNameAndOwner) | ||
| end | ||
| return removedPrimaryNamesAndOwners | ||
|
|
@@ -272,6 +285,12 @@ function primaryNames.removePrimaryName(name, from) | |
| if PrimaryNames.requests[primaryName.owner] and PrimaryNames.requests[primaryName.owner].name == name then | ||
| PrimaryNames.requests[primaryName.owner] = nil | ||
| end | ||
|
|
||
| -- track the changes in the hyperbeam sync | ||
| HyperbeamSync.primaryNames.names[name] = true | ||
| HyperbeamSync.primaryNames.owners[primaryName.owner] = true | ||
| HyperbeamSync.primaryNames.requests[primaryName.owner] = true | ||
|
|
||
| return { | ||
| name = name, | ||
| owner = primaryName.owner, | ||
|
|
@@ -348,6 +367,9 @@ function primaryNames.removePrimaryNamesForBaseName(baseName) | |
| local primaryNamesForBaseName = primaryNames.getPrimaryNamesForBaseName(baseName) | ||
| for _, nameData in pairs(primaryNamesForBaseName) do | ||
| local removedName = primaryNames.removePrimaryName(nameData.name, nameData.owner) | ||
| -- track the changes in the hyperbeam sync | ||
| HyperbeamSync.primaryNames.names[nameData.name] = true | ||
| HyperbeamSync.primaryNames.owners[nameData.owner] = true | ||
| table.insert(removedNames, removedName) | ||
| end | ||
| return removedNames | ||
|
|
@@ -410,6 +432,9 @@ function primaryNames.prunePrimaryNameRequests(timestamp) | |
| if request.endTimestamp <= timestamp then | ||
| PrimaryNames.requests[initiator] = nil | ||
| prunedNameRequests[initiator] = request | ||
|
|
||
| -- track the changes in the hyperbeam sync | ||
| HyperbeamSync.primaryNames.requests[initiator] = true | ||
| else | ||
| primaryNames.scheduleNextPrimaryNamesPruning(request.endTimestamp) | ||
| end | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| import { | ||
| assertNoResultError, | ||
| buyRecord, | ||
| handle, | ||
| startMemory, | ||
| totalTokenSupply, | ||
| transfer, | ||
| } from './helpers.mjs'; | ||
| import assert from 'assert'; | ||
| import { describe, it } from 'node:test'; | ||
| import { STUB_TIMESTAMP } from '../tools/constants.mjs'; | ||
|
|
||
| describe('Primary Names Hyperbeam Patching', function () { | ||
| it('should send patch with request when primary name request is created', async () => { | ||
| const testTimestamp = STUB_TIMESTAMP + 1000; | ||
| const testCaller = 'test-caller-address-'.padEnd(43, '1'); | ||
| const baseNameOwner = 'base-name-owner-address-'.padEnd(43, '2'); | ||
| const testName = 'test-name'; | ||
| const testProcessId = 'test-process-id-'.padEnd(43, '1'); | ||
|
|
||
| // Initialize token supply | ||
| const { Memory: totalTokenSupplyMemory } = await totalTokenSupply({ | ||
| memory: startMemory, | ||
| }); | ||
| let memory = totalTokenSupplyMemory; | ||
|
|
||
| // Give both addresses balance | ||
| let result = await transfer({ | ||
| recipient: baseNameOwner, | ||
| quantity: 10000000000, | ||
| memory, | ||
| timestamp: testTimestamp, | ||
| }); | ||
| memory = result; | ||
|
|
||
| result = await transfer({ | ||
| recipient: testCaller, | ||
| quantity: 10000000000, | ||
| memory, | ||
| timestamp: testTimestamp + 10, | ||
| }); | ||
| memory = result; | ||
|
|
||
| // Base name owner buys the ArNS record | ||
| result = await buyRecord({ | ||
| memory, | ||
| from: baseNameOwner, | ||
| name: testName, | ||
| processId: testProcessId, | ||
| type: 'permabuy', | ||
| timestamp: testTimestamp + 100, | ||
| }); | ||
| memory = result.memory; | ||
|
|
||
| // Request primary name from a different caller than the base name owner | ||
| const requestResult = await handle({ | ||
| options: { | ||
| From: testCaller, | ||
| Owner: testCaller, | ||
| Timestamp: testTimestamp + 200, | ||
| Tags: [ | ||
| { name: 'Action', value: 'Request-Primary-Name' }, | ||
| { name: 'Name', value: testName }, | ||
| ], | ||
| }, | ||
| memory, | ||
| }); | ||
|
|
||
| assertNoResultError(requestResult); | ||
|
|
||
| // Find the patch message with device: "[email protected]" | ||
| const messages = requestResult.Messages || []; | ||
| let patchMessage = null; | ||
| for (let i = messages.length - 1; i >= 0; i--) { | ||
| const tags = messages[i].Tags || []; | ||
| const deviceTag = tags.find((t) => t.name === 'device'); | ||
| if (deviceTag && deviceTag.value === '[email protected]') { | ||
| patchMessage = messages[i]; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| assert(patchMessage, 'Should send a patch message'); | ||
|
|
||
| // Get the primary-names tag | ||
| const primaryNamesTag = patchMessage.Tags.find( | ||
| (t) => t.name === 'primary-names', | ||
| ); | ||
| assert(primaryNamesTag, 'Patch should have primary-names tag'); | ||
|
|
||
| // Patch messages don't JSON-encode on purpose, so the value is already an object | ||
| const patch = primaryNamesTag.value; | ||
|
|
||
| assert(patch, 'Should have primary names patch data'); | ||
| assert(patch.requests, 'Patch should include requests'); | ||
| assert( | ||
| patch.requests[testCaller], | ||
| 'Patch should include the request for the caller', | ||
| ); | ||
| assert.strictEqual( | ||
| patch.requests[testCaller].name, | ||
| testName, | ||
| 'Request should have correct name', | ||
| ); | ||
| }); | ||
| }); |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nits:
The principleand weird tabbing on the line below.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
8082bad