diff --git a/backend/src/import-from-ss.js b/backend/src/import-from-ss.js index 519d7c1..75e6119 100644 --- a/backend/src/import-from-ss.js +++ b/backend/src/import-from-ss.js @@ -58,9 +58,7 @@ const fetchWithRetry = async (url, retryDelay = 5000) => { throw requestError; } else if (retry) { console.log('retry delay (sec):', retryDelay / 1000); - await new Promise((resolve) => { - setTimeout(resolve, retryDelay); - }); + await Promise.delay(retryDelay); responseData = await fetchWithRetry(url, retryDelay * 2); } else { responseData = response.data; @@ -153,6 +151,22 @@ HREF ${paper.url}`; }; }; +const addPostWithRetry = async (authors, hash, citations, retryDelay = 5000) => { + try { + await dao.addPost(authors, hash, citations); + } 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); + } if (e.reason === 'A post with this contentId already exists') { + return { alreadyAdded: true }; + } + throw e; + } + return { alreadyAdded: false }; +}; + const importPaper = async (paper) => { console.log('references count:', paper.references.length); const { paperId } = paper; @@ -188,19 +202,15 @@ const importPaper = async (paper) => { authors, content, signature, embeddedData, citations, }); - // Add the post to the form (on-chain) - try { - await dao.addPost(authors, hash, citations); - } catch (e) { - if (e.reason === 'A post with this contentId already exists') { - console.log(`Post already added for paper ${paperId}`); - return { paperId, postId: hash, alreadyAdded: true }; - } - throw e; + // Add the post to the forum (on-chain) + const { alreadyAdded } = await addPostWithRetry(authors, hash, citations); + if (alreadyAdded) { + console.log(`Post already added for paper ${paperId}`); + } else { + console.log(`Added post to blockchain for paper ${paperId}`); } - console.log(`Added post to blockchain for paper ${paperId}`); - return { paperId, postId: hash }; + return { paperId, postId: hash, alreadyAdded }; }; module.exports = async (req, res) => { diff --git a/ethereum/contracts/Proposals.sol b/ethereum/contracts/Proposals.sol index 35bc99a..d7c258a 100644 --- a/ethereum/contracts/Proposals.sol +++ b/ethereum/contracts/Proposals.sol @@ -5,8 +5,6 @@ import "./core/DAO.sol"; import "./interfaces/IOnValidate.sol"; import "./interfaces/IOnProposalAccepted.sol"; -import "hardhat/console.sol"; - contract Proposals is DAOContract, IOnValidate { enum Stage { Proposal, diff --git a/ethereum/contracts/WorkContract.sol b/ethereum/contracts/WorkContract.sol index 50acea8..2bf3909 100644 --- a/ethereum/contracts/WorkContract.sol +++ b/ethereum/contracts/WorkContract.sol @@ -6,7 +6,6 @@ import "./core/Forum.sol"; import "./Proposals.sol"; import "./interfaces/IAcceptAvailability.sol"; import "./interfaces/IOnProposalAccepted.sol"; -import "hardhat/console.sol"; abstract contract WorkContract is DAOContract, diff --git a/ethereum/contracts/core/DAO.sol b/ethereum/contracts/core/DAO.sol index 41c64e4..023454e 100644 --- a/ethereum/contracts/core/DAO.sol +++ b/ethereum/contracts/core/DAO.sol @@ -6,7 +6,6 @@ import "./Reputation.sol"; import "./ValidationPools.sol"; import "./Forum.sol"; import "../interfaces/IAcceptAvailability.sol"; -import "hardhat/console.sol"; contract DAO is Reputation, Forum, ValidationPools { /// Authorize a contract to transfer REP, and call that contract's acceptAvailability method diff --git a/ethereum/contracts/core/Forum.sol b/ethereum/contracts/core/Forum.sol index c49d8fa..209c87a 100644 --- a/ethereum/contracts/core/Forum.sol +++ b/ethereum/contracts/core/Forum.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.24; import "./Reputation.sol"; -import "hardhat/console.sol"; struct Citation { int weightPPM; @@ -23,6 +22,12 @@ struct Post { // TODO: timestamp } +// struct PostParams { +// string contentId; +// Author[] authors; +// Citation[] citations; +// } + contract Forum is Reputation { mapping(string => Post) public posts; string[] public postIds; @@ -88,6 +93,16 @@ contract Forum is Reputation { emit PostAdded(contentId); } + // function addPosts(PostParams[] calldata postParams) external { + // for (uint i = 0; i < postParams.length; i++) { + // this.addPost( + // postParams[i].authors, + // postParams[i].contentId, + // postParams[i].citations + // ); + // } + // } + function getPostAuthors( string calldata postId ) external view returns (Author[] memory) { @@ -95,10 +110,6 @@ contract Forum is Reputation { return post.authors; } - function _onValidatePost(string memory postId, uint amount) internal { - _propagateReputation(postId, int(amount), false, 0); - } - function _handleCitation( string memory postId, Citation memory citation, diff --git a/ethereum/contracts/core/ValidationPools.sol b/ethereum/contracts/core/ValidationPools.sol index 969b80f..391906d 100644 --- a/ethereum/contracts/core/ValidationPools.sol +++ b/ethereum/contracts/core/ValidationPools.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.24; import "./Reputation.sol"; import "./Forum.sol"; import "../interfaces/IOnValidate.sol"; -import "hardhat/console.sol"; struct ValidationPoolStake { uint id; @@ -243,7 +242,12 @@ contract ValidationPools is Reputation, Forum { } // Transfer REP to the forum instead of to the author directly - _onValidatePost(pool.postId, pool.minted / 2 + remainder); + _propagateReputation( + pool.postId, + int(pool.minted / 2 + remainder), + false, + 0 + ); } else { // If vote does not pass, divide the losing stake among the winners totalRewards += pool.minted; diff --git a/ethereum/test/Forum.js b/ethereum/test/Forum.js index 7dcfe35..7d5697a 100644 --- a/ethereum/test/Forum.js +++ b/ethereum/test/Forum.js @@ -63,6 +63,37 @@ describe('Forum', () => { expect(postAuthors[0].authorAddress).to.equal(account1); }); + // it('should be able to add multiple posts', async () => { + // await expect(dao.addPost([{ + // authors: [{ weightPPM: 100, authorAddress: account1 }], + // contentId: 'some-id', + // citations: [], + // }, { + // authors: [{ weightPPM: 100, authorAddress: account2 }], + // contentId: 'some-other-id', + // citations: [], + + // }, + // ])) + // .to.emit(dao, 'PostAdded').withArgs('some-id') + // .to.emit(dao, 'PostAdded').withArgs('some-other-id'); + // let post = await dao.posts('some-id'); + // expect(post.sender).to.equal(account1); + // expect(post.id).to.equal('some-id'); + // let postAuthors = await dao.getPostAuthors('some-id'); + // expect(postAuthors).to.have.length(1); + // expect(postAuthors[0].weightPPM).to.equal(1000000); + // expect(postAuthors[0].authorAddress).to.equal(account1); + + // post = await dao.posts('some-other-id'); + // expect(post.sender).to.equal(account2); + // expect(post.id).to.equal('some-other-id'); + // postAuthors = await dao.getPostAuthors('some-other-id'); + // expect(postAuthors).to.have.length(1); + // expect(postAuthors[0].weightPPM).to.equal(1000000); + // expect(postAuthors[0].authorAddress).to.equal(account2); + // }); + it('should be able to add a post on behalf of another account', async () => { const contentId = 'some-id'; await addPost(account2, contentId, []);