diff --git a/backend/src/api/import-from-matrix.js b/backend/src/api/import-from-matrix.js index 867b1b3..cbb018e 100644 --- a/backend/src/api/import-from-matrix.js +++ b/backend/src/api/import-from-matrix.js @@ -42,8 +42,8 @@ module.exports = async (req, res) => { // We want to add a post representing this matrix message. const authors = [{ authorAddress, weightPPM: 1000000 }]; - // TODO: Take citations as input to this API call, referencing other posts or matrix events - const citations = []; + // TODO: Take references as input to this API call, referencing other posts or matrix events + const references = []; const content = `Matrix event URI: ${eventUri}`; const embeddedData = { roomId, @@ -55,11 +55,11 @@ module.exports = async (req, res) => { const signature = await wallet.signMessage(contentToVerify); const { hash } = await write({ - sender, authors, citations, content, embeddedData, signature, + sender, authors, references, content, embeddedData, signature, }); // Now we want to add a post on-chain - const { alreadyAdded } = await addPostWithRetry(authors, hash, citations); + const { alreadyAdded } = await addPostWithRetry(authors, hash, references); if (alreadyAdded) { console.log(`Post already added for matrix event ${eventUri}`); diff --git a/backend/src/api/import-from-ss.js b/backend/src/api/import-from-ss.js index 98b254c..89e4b0a 100644 --- a/backend/src/api/import-from-ss.js +++ b/backend/src/api/import-from-ss.js @@ -8,8 +8,8 @@ const { authorAddresses, authorPrivKeys } = require('../util/db'); const { dao } = require('../util/contracts'); const write = require('../util/forum/write'); -// Each post allocates 30% of its reputation to citations -const PPM_TO_CITATIONS = 300000; +// Each post allocates 30% of its reputation to references +const PPM_TO_REFERENCES = 300000; const fetchWithRetry = async (url, retryDelay = 5000) => { let retry = false; @@ -116,14 +116,14 @@ HREF ${paper.url}`; }; }; -const addPostWithRetry = async (authors, hash, citations, retryDelay = 5000) => { +const addPostWithRetry = async (authors, hash, references, retryDelay = 5000) => { try { - await dao.addPost(authors, hash, citations); + await dao.addPost(authors, hash, references); } catch (e) { if (e.code === 'REPLACEMENT_UNDERPRICED') { console.log('retry delay (sec):', retryDelay / 1000); await Promise.delay(retryDelay); - return addPostWithRetry(authors, hash, citations, retryDelay * 2); + return addPostWithRetry(authors, hash, references, retryDelay * 2); } if (e.reason === 'A post with this postId already exists') { return { alreadyAdded: true }; } @@ -136,18 +136,18 @@ const importPaper = async (paper) => { console.log('references count:', paper.references.length); const { paperId } = paper; const references = paper.references.filter((x) => !!x.paperId); - const eachCitationWeightPPM = Math.floor(PPM_TO_CITATIONS / references.length); - const citations = (await Promise.mapSeries( + const eachReferenceWeightPPM = Math.floor(PPM_TO_REFERENCES / references.length); + const references = (await Promise.mapSeries( references, async (citedPaper) => { // We need to fetch this paper so we can generate the post we WOULD add to the forum. // That way, if we later add the cited paper to the blockchain it will have the correct hash. - // The forum allows dangling citations to support this use case. + // The forum allows dangling references to support this use case. try { const citedPost = await generatePost(citedPaper); const citedPostHash = objectHash(citedPost); return { - weightPPM: eachCitationWeightPPM, + weightPPM: eachReferenceWeightPPM, targetPostId: citedPostHash, }; } catch (e) { @@ -156,10 +156,10 @@ const importPaper = async (paper) => { }, )).filter((x) => !!x); - // Make sure citation weights sum to the designated total - if (citations.length) { - const totalCitationWeight = citations.reduce((t, { weightPPM }) => t + weightPPM, 0); - citations[0].weightPPM += PPM_TO_CITATIONS - totalCitationWeight; + // Make sure reference weights sum to the designated total + if (references.length) { + const totalReferenceWeight = references.reduce((t, { weightPPM }) => t + weightPPM, 0); + references[0].weightPPM += PPM_TO_REFERENCES - totalReferenceWeight; } // Create a post for this paper @@ -169,12 +169,12 @@ const importPaper = async (paper) => { // Write the new post to our database const { hash } = await write({ - authors, content, signature, embeddedData, citations, + authors, content, signature, embeddedData, references, }); // Add the post to the forum (on-chain) - console.log('addPostWithRetry', { authors, hash, citations }); - const { alreadyAdded } = await addPostWithRetry(authors, hash, citations); + console.log('addPostWithRetry', { authors, hash, references }); + const { alreadyAdded } = await addPostWithRetry(authors, hash, references); if (alreadyAdded) { console.log(`Post already added for paper ${paperId}`); } else { diff --git a/backend/src/event-handlers/rollup/batch/submit-rollup.js b/backend/src/event-handlers/rollup/batch/submit-rollup.js index cf60abd..cbcf9ea 100644 --- a/backend/src/event-handlers/rollup/batch/submit-rollup.js +++ b/backend/src/event-handlers/rollup/batch/submit-rollup.js @@ -33,8 +33,8 @@ const submitRollup = async () => { if (!authors.length) { return { batchItems: [] }; } - // TODO: Compute citations as aggregate of the citations of posts in the batch - const citations = []; + // TODO: Compute references as aggregate of the references of posts in the batch + const references = []; const content = `Batch of ${batchItems.length} items`; const embeddedData = { batchItems, @@ -45,11 +45,11 @@ const submitRollup = async () => { const signature = await wallet.signMessage(contentToVerify); // Write to the forum database const { hash: batchPostId } = await write({ - sender, authors, citations, content, embeddedData, signature, + sender, authors, references, content, embeddedData, signature, }); // Add rollup post on-chain - console.log('adding batch post on-chain', { authors, batchPostId, citations }); - await addPostWithRetry(authors, batchPostId, citations); + console.log('adding batch post on-chain', { authors, batchPostId, references }); + await addPostWithRetry(authors, batchPostId, references); // Stake our availability to be the next rollup worker console.log('staking availability to be the next rollup worker'); await stakeRollupAvailability(); diff --git a/backend/src/util/add-post-with-retry.js b/backend/src/util/add-post-with-retry.js index 667be2f..68be4ba 100644 --- a/backend/src/util/add-post-with-retry.js +++ b/backend/src/util/add-post-with-retry.js @@ -1,9 +1,9 @@ const callWithRetry = require('./call-with-retry'); const { dao } = require('./contracts'); -const addPostWithRetry = async (authors, hash, citations) => { +const addPostWithRetry = async (authors, hash, references) => { try { - await callWithRetry(() => dao.addPost(authors, hash, citations)); + await callWithRetry(() => dao.addPost(authors, hash, references)); } catch (e) { if (e.reason === 'A post with this postId already exists') { return { alreadyAdded: true }; diff --git a/backend/src/util/forum/read.js b/backend/src/util/forum/read.js index 988fd13..727bea1 100644 --- a/backend/src/util/forum/read.js +++ b/backend/src/util/forum/read.js @@ -10,7 +10,7 @@ const read = async (hash) => { data.embeddedData = data.embeddedData || undefined; const { - sender, authors, content, signature, embeddedData, citations, + sender, authors, content, signature, embeddedData, references, } = data; // Verify hash @@ -29,7 +29,7 @@ const read = async (hash) => { } return { - sender, authors, content, signature, embeddedData, citations, + sender, authors, content, signature, embeddedData, references, }; }; diff --git a/backend/src/util/forum/write.js b/backend/src/util/forum/write.js index 8f0b070..5d1fdea 100644 --- a/backend/src/util/forum/write.js +++ b/backend/src/util/forum/write.js @@ -4,7 +4,7 @@ const verifySignature = require('../verify-signature'); const { forum } = require('../db'); const write = async ({ - sender, authors, content, citations, embeddedData, signature, + sender, authors, content, references, embeddedData, signature, }) => { // Check author signature if (!verifySignature({ @@ -18,9 +18,9 @@ const write = async ({ // Compute content hash const data = { - sender, authors, content, signature, embeddedData, citations, + sender, authors, content, signature, embeddedData, references, }; - // We omit citations from the hash in order to support forum graph import. + // We omit references from the hash in order to support forum graph import. // When a post is imported, the hashes can be precomputed for cited posts, // without traversing the graph infinitely to compute hashes along entire reference chain. const hash = objectHash({ diff --git a/ethereum/contracts/Onboarding.sol b/ethereum/contracts/Onboarding.sol index 2913d82..cfd765c 100644 --- a/ethereum/contracts/Onboarding.sol +++ b/ethereum/contracts/Onboarding.sol @@ -29,7 +29,7 @@ contract Onboarding is Work, IOnValidate { // Make work evidence post Author[] memory authors = new Author[](1); authors[0] = Author(1000000, stake.worker); - dao.addPost(authors, request.evidencePostId, request.citations); + dao.addPost(authors, request.evidencePostId, request.references); emit WorkApprovalSubmitted(requestIndex, approval); // Initiate validation pool uint poolIndex = dao.initiateValidationPool{ @@ -73,10 +73,10 @@ contract Onboarding is Work, IOnValidate { return; } // Make onboarding post - Citation[] memory emptyCitations; + Reference[] memory emptyReferences; Author[] memory authors = new Author[](1); authors[0] = Author(1000000, request.customer); - dao.addPost(authors, request.requestPostId, emptyCitations); + dao.addPost(authors, request.requestPostId, emptyReferences); dao.initiateValidationPool{value: request.fee / 10}( request.requestPostId, POOL_DURATION, diff --git a/ethereum/contracts/RollableWork.sol b/ethereum/contracts/RollableWork.sol index e61bc97..6740260 100644 --- a/ethereum/contracts/RollableWork.sol +++ b/ethereum/contracts/RollableWork.sol @@ -34,7 +34,7 @@ abstract contract RollableWork is Work { // Make work evidence post Author[] memory authors = new Author[](1); authors[0] = Author(1000000, stake.worker); - dao.addPost(authors, request.evidencePostId, request.citations); + dao.addPost(authors, request.evidencePostId, request.references); // send worker stakes and customer fee to rollup contract dao.forwardAllowance( diff --git a/ethereum/contracts/Work.sol b/ethereum/contracts/Work.sol index a42f684..e967a4e 100644 --- a/ethereum/contracts/Work.sol +++ b/ethereum/contracts/Work.sol @@ -22,7 +22,7 @@ abstract contract Work is Availability, IOnProposalAccepted { uint stakeIndex; string requestPostId; string evidencePostId; - Citation[] citations; + Reference[] references; bool approval; } @@ -71,7 +71,7 @@ abstract contract Work is Availability, IOnProposalAccepted { function submitWorkEvidence( uint requestIndex, string calldata evidencePostId, - Citation[] calldata citations + Reference[] calldata references ) external { WorkRequest storage request = requests[requestIndex]; require( @@ -85,8 +85,8 @@ abstract contract Work is Availability, IOnProposalAccepted { ); request.status = WorkStatus.EvidenceSubmitted; request.evidencePostId = evidencePostId; - for (uint i = 0; i < citations.length; i++) { - request.citations.push(citations[i]); + for (uint i = 0; i < references.length; i++) { + request.references.push(references[i]); } emit WorkEvidenceSubmitted(requestIndex); } @@ -107,7 +107,7 @@ abstract contract Work is Availability, IOnProposalAccepted { // Make work evidence post Author[] memory authors = new Author[](1); authors[0] = Author(1000000, stake.worker); - dao.addPost(authors, request.evidencePostId, request.citations); + dao.addPost(authors, request.evidencePostId, request.references); emit WorkApprovalSubmitted(requestIndex, approval); // Initiate validation pool uint poolIndex = dao.initiateValidationPool{value: request.fee}( diff --git a/ethereum/contracts/core/DAO.sol b/ethereum/contracts/core/DAO.sol index 3500fc4..88d4903 100644 --- a/ethereum/contracts/core/DAO.sol +++ b/ethereum/contracts/core/DAO.sol @@ -251,9 +251,9 @@ contract DAO { function addPost( Author[] calldata authors, string calldata postId, - Citation[] calldata citations + Reference[] calldata references ) public { - forum.addPost(msg.sender, authors, postId, citations); + forum.addPost(msg.sender, authors, postId, references); } function posts( diff --git a/ethereum/contracts/core/Forum.sol b/ethereum/contracts/core/Forum.sol index 25b44c1..d3b3ada 100644 --- a/ethereum/contracts/core/Forum.sol +++ b/ethereum/contracts/core/Forum.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.24; import "./DAO.sol"; -struct Citation { +struct Reference { int weightPPM; string targetPostId; } @@ -17,7 +17,7 @@ struct Post { string id; address sender; Author[] authors; - Citation[] citations; + Reference[] references; uint reputation; // TODO: timestamp } @@ -47,7 +47,7 @@ contract Forum { address sender, Author[] calldata authors, string calldata postId, - Citation[] calldata citations + Reference[] calldata references ) external { require( msg.sender == address(dao), @@ -72,31 +72,31 @@ contract Forum { authorTotalWeightPPM == 1000000, "Author weights must sum to 1000000" ); - for (uint i = 0; i < citations.length; i++) { - post.citations.push(citations[i]); + for (uint i = 0; i < references.length; i++) { + post.references.push(references[i]); } - int totalCitationWeightPos; - int totalCitationWeightNeg; - for (uint i = 0; i < post.citations.length; i++) { - int weight = post.citations[i].weightPPM; + int totalReferenceWeightPos; + int totalReferenceWeightNeg; + for (uint i = 0; i < post.references.length; i++) { + int weight = post.references[i].weightPPM; require( weight >= -1000000, - "Each citation weight must be >= -1000000" + "Each reference weight must be >= -1000000" ); require( weight <= 1000000, - "Each citation weight must be <= 1000000" + "Each reference weight must be <= 1000000" ); - if (weight > 0) totalCitationWeightPos += weight; - else totalCitationWeightNeg += weight; + if (weight > 0) totalReferenceWeightPos += weight; + else totalReferenceWeightNeg += weight; } require( - totalCitationWeightPos <= 1000000, - "Sum of positive citations must be <= 1000000" + totalReferenceWeightPos <= 1000000, + "Sum of positive references must be <= 1000000" ); require( - totalCitationWeightNeg >= -1000000, - "Sum of negative citations must be >= -1000000" + totalReferenceWeightNeg >= -1000000, + "Sum of negative references must be >= -1000000" ); dao.emitPostAdded(postId); } @@ -108,15 +108,15 @@ contract Forum { return post.authors; } - function _handleCitation( + function _handleReference( string memory postId, - Citation memory citation, + Reference memory ref, int amount, bool initialNegative, uint depth ) internal returns (int outboundAmount) { - outboundAmount = (amount * citation.weightPPM) / 1000000; - if (bytes(citation.targetPostId).length == 0) { + outboundAmount = (amount * ref.weightPPM) / 1000000; + if (bytes(ref.targetPostId).length == 0) { // Incineration require( outboundAmount >= 0, @@ -125,7 +125,7 @@ contract Forum { dao.burn(address(dao), uint(outboundAmount)); return outboundAmount; } - int balanceToOutbound = _edgeBalances[postId][citation.targetPostId]; + int balanceToOutbound = _edgeBalances[postId][ref.targetPostId]; if (initialNegative) { if (outboundAmount < 0) { outboundAmount = outboundAmount > -balanceToOutbound @@ -138,13 +138,13 @@ contract Forum { } } int refund = propagateReputation( - citation.targetPostId, + ref.targetPostId, outboundAmount, - initialNegative || (depth == 0 && citation.weightPPM < 0), + initialNegative || (depth == 0 && ref.weightPPM < 0), depth + 1 ); outboundAmount -= refund; - _edgeBalances[postId][citation.targetPostId] += outboundAmount; + _edgeBalances[postId][ref.targetPostId] += outboundAmount; } function _distributeAmongAuthors( @@ -200,28 +200,28 @@ contract Forum { } Post storage post = posts[postId]; if (post.authors.length == 0) { - // We most likely got here via a citation to a post that hasn't been added yet. - // We support this scenario so that a citation graph can be imported one post at a time. + // We most likely got here via a reference to a post that hasn't been added yet. + // We support this scenario so that a reference graph can be imported one post at a time. return amount; } - // Propagate negative citations first - for (uint i = 0; i < post.citations.length; i++) { - if (post.citations[i].weightPPM < 0) { - amount -= _handleCitation( + // Propagate negative references first + for (uint i = 0; i < post.references.length; i++) { + if (post.references[i].weightPPM < 0) { + amount -= _handleReference( postId, - post.citations[i], + post.references[i], amount, initialNegative, depth ); } } - // Now propagate positive citations - for (uint i = 0; i < post.citations.length; i++) { - if (post.citations[i].weightPPM > 0) { - amount -= _handleCitation( + // Now propagate positive references + for (uint i = 0; i < post.references.length; i++) { + if (post.references[i].weightPPM > 0) { + amount -= _handleReference( postId, - post.citations[i], + post.references[i], amount, initialNegative, depth diff --git a/ethereum/test/Forum.js b/ethereum/test/Forum.js index 5b3f4e0..516422d 100644 --- a/ethereum/test/Forum.js +++ b/ethereum/test/Forum.js @@ -39,10 +39,10 @@ describe('Forum', () => { { value: fee ?? POOL_FEE }, ); - const addPost = (author, postId, citations) => dao.addPost([{ + const addPost = (author, postId, references) => dao.addPost([{ weightPPM: 1000000, authorAddress: author, - }], postId, citations); + }], postId, references); describe('Post', () => { beforeEach(async () => { @@ -113,7 +113,7 @@ describe('Forum', () => { ], postId, [])).to.be.rejectedWith('Author weights must sum to 1000000'); }); - it('should be able to donate reputation via citations', async () => { + it('should be able to donate reputation via references', async () => { await addPost(account1, 'content-id', []); await addPost(account2, 'second-content-id', [{ weightPPM: 500000, targetPostId: 'content-id' }]); await initiateValidationPool({ postId: 'second-content-id' }); @@ -124,7 +124,7 @@ describe('Forum', () => { expect(await dao.balanceOf(account2)).to.equal(50); }); - it('should be able to leach reputation via citations', async () => { + it('should be able to leach reputation via references', async () => { await addPost(account1, 'content-id', []); expect((await dao.posts('content-id')).reputation).to.equal(0); await initiateValidationPool({ postId: 'content-id' }); @@ -144,7 +144,7 @@ describe('Forum', () => { expect((await dao.posts('second-content-id')).reputation).to.equal(150); }); - it('should be able to redistribute power via citations', async () => { + it('should be able to redistribute power via references', async () => { await addPost(account1, 'content-id', []); await initiateValidationPool({ postId: 'content-id' }); await dao.evaluateOutcome(0); @@ -165,7 +165,7 @@ describe('Forum', () => { expect(await dao.balanceOf(account3)).to.equal(0); }); - it('should be able to reverse a negative citation with a negative citation', async () => { + it('should be able to reverse a negative reference with a negative reference', async () => { await addPost(account1, 'content-id', []); await initiateValidationPool({ postId: 'content-id' }); await dao.evaluateOutcome(0); @@ -294,7 +294,7 @@ describe('Forum', () => { expect(await dao.totalSupply()).to.equal(50); }); - describe('negative citation of a post, the author having already staked and lost reputation', async () => { + describe('negative reference of a post, the author having already staked and lost reputation', async () => { beforeEach(async () => { await addPost(account1, 'content-id', []); await initiateValidationPool({ postId: 'content-id' }); @@ -372,7 +372,7 @@ describe('Forum', () => { }); }); - describe('negative citation of a post with multiple authors', async () => { + describe('negative reference of a post with multiple authors', async () => { beforeEach(async () => { await dao.addPost([ { weightPPM: 500000, authorAddress: account1 }, diff --git a/frontend/src/components/posts/ViewPostModal.jsx b/frontend/src/components/posts/ViewPostModal.jsx index 715ad58..7ffc898 100644 --- a/frontend/src/components/posts/ViewPostModal.jsx +++ b/frontend/src/components/posts/ViewPostModal.jsx @@ -8,7 +8,7 @@ function ViewPostModal({ }) { const handleClose = () => setShow(false); const { - content, authors, embeddedData, citations, + content, authors, embeddedData, references, } = post; const embeddedDataJson = JSON.stringify(embeddedData, null, 2); @@ -46,12 +46,12 @@ function ViewPostModal({ {embeddedDataJson} )} - {citations && citations.length > 0 && ( + {references && references.length > 0 && ( <>