Skip to content

Conversation

@Canvinus
Copy link
Contributor

@Canvinus Canvinus commented Dec 2, 2025

This pull request introduces several foundational changes to the project, focusing on contract data modeling, serialization utilities, and build configuration updates. The main highlights are the addition of new modules for handling votes and comments within verified contracts, custom serialization logic for numeric types, and updates to dependencies and toolchain versions for improved compatibility and reproducibility.

Data Model Enhancements

  • Added new modules: src/verified_contract/vote.rs and src/verified_contract/comment.rs, introducing Vote, VoteType, and Comment structs for tracking votes and comments on verified contracts, including custom equality, ordering, and hashing logic for votes. [1] [2]
  • Updated src/verified_contract/mod.rs to define the VerifiedContract struct, which now includes votes and comments, and to expose the new modules.

Serialization Utilities

  • Added src/str_serializers.rs with custom serialization/deserialization logic for u64 and u128 types, ensuring numeric fields are stored as strings in JSON.
  • Integrated these serializers into the new data models for timestamp fields in votes and comments. [1] [2]

Build and Dependency Updates

  • Updated Cargo.toml:
    • Changed the project description and repository URL.
    • Upgraded near-sdk and related dependencies to newer versions.
    • Added reproducible build metadata for Docker-based builds.
  • Updated rust-toolchain.toml to use Rust 1.85.0 for better compatibility.
  • Added .vscode/settings.json for Rust Analyzer project configuration.

Test Adjustments

  • Removed usage of the old ContractData struct in tests and updated the operational test to initialize the contract before other calls. [1] [2] [3]

Canvinus and others added 7 commits August 9, 2024 17:35
- add get_contracts_by_code_hash() to find verified contracts by hash
- add get_contracts_count() to return total verified contracts
- add unit tests for new functions
- update rust toolchain to 1.85.0
- update dependencies
Copilot AI review requested due to automatic review settings December 2, 2025 12:07
@Canvinus Canvinus merged commit 18aea3e into main Dec 2, 2025
1 of 3 checks passed
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request introduces significant foundational changes to transform the verifier contract into a comprehensive verification registry with social features. The main purpose is to add voting and commenting capabilities to verified contracts while modernizing the codebase with updated dependencies and build configurations.

Key Changes:

  • New data models for votes and comments on verified contracts with custom serialization for timestamps
  • Simplified contract verification model removing GitHub metadata and build configuration fields
  • Updated dependencies (near-sdk 5.2.1) and Rust toolchain (1.85.0) with reproducible build support

Reviewed changes

Copilot reviewed 9 out of 11 changed files in this pull request and generated 22 comments.

Show a summary per file
File Description
src/verified_contract/vote.rs Introduces Vote and VoteType structs with custom equality/ordering logic for tracking user votes
src/verified_contract/comment.rs Defines Comment struct for storing user comments with votes and timestamps
src/verified_contract/mod.rs Declares VerifiedContract struct with simplified fields and collections for votes/comments
src/str_serializers.rs Provides custom serializers for u64/u128 to ensure numeric fields serialize as strings in JSON
src/lib.rs Major refactor adding voting/commenting methods, updating contract storage structure, and simplifying verification data
tests/test_basics.rs Updates integration test to initialize contract and removes obsolete assertions for removed fields
Cargo.toml Updates dependencies to near-sdk 5.2.1, adds reproducible build configuration with Docker image metadata
rust-toolchain.toml Updates Rust version from 1.73.0 to 1.85.0
.vscode/settings.json Adds Rust Analyzer configuration for the project
.gitignore Adds entries for backups and build scripts

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

self.contracts.insert(&account_id, &contract);
log!("Vote updated for contract {}", account_id);
}

Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The add_comment public function lacks documentation. Users need to understand:

  • Maximum comment length (if any)
  • Whether empty comments are allowed
  • What the comment ID will be and how to reference it

Solution: Add documentation:

/// Adds a comment to a verified contract.
/// 
/// # Arguments
/// * `account_id` - The account ID of the contract to comment on
/// * `content` - The text content of the comment
/// 
/// # Panics
/// Panics if the contract is not found
pub fn add_comment(&mut self, account_id: AccountId, content: String) {
Suggested change
/// Adds a comment to a verified contract.
///
/// # Arguments
/// * `account_id` - The account ID of the contract to comment on.
/// * `content` - The text content of the comment.
///
/// # Details
/// - Maximum comment length: No explicit limit is enforced in this function.
/// - Empty comments: Allowed (no explicit check).
/// - Comment ID: The comment ID is assigned as the current number of comments (`self.comments.len() as u64`).
/// You can reference a comment by its ID as returned in the `Comment` struct.
///
/// # Panics
/// Panics if the contract is not found for the given `account_id`.

Copilot uses AI. Check for mistakes.

return (filtered, pages);
}

Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The vote_comment public function lacks documentation. Users need to understand:

  • How to obtain comment IDs
  • What happens if they vote multiple times
  • Whether the comment must exist

Solution: Add documentation:

/// Adds or updates a vote for a comment.
/// If the user has already voted on this comment, their previous vote is replaced.
/// 
/// # Arguments
/// * `comment_id` - The ID of the comment to vote on
/// * `is_upvote` - true for upvote, false for downvote
/// 
/// # Panics
/// Panics if the comment is not found
pub fn vote_comment(&mut self, comment_id: u64, is_upvote: bool) {
Suggested change
/// Adds or updates a vote for a comment.
///
/// # Arguments
/// * `comment_id` - The ID of the comment to vote on. You can obtain comment IDs using the `get_comments` method.
/// * `is_upvote` - `true` for upvote, `false` for downvote.
///
/// # Behavior
/// If the caller has already voted on this comment, their previous vote is replaced with the new one.
///
/// # Panics
/// Panics if the comment with the given ID does not exist.

Copilot uses AI. Check for mistakes.
pub code_hash: String,
pub block_height: u64,
pub votes: HashSet<Vote>,
pub comments: Vec<u64>,
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The field name comments is misleading as it stores comment IDs (Vec<u64>), not actual Comment objects. This could confuse developers who might expect to access comment data directly.

Solution: Rename the field to better reflect its purpose, such as comment_ids or comment_references:

pub comment_ids: Vec<u64>,
Suggested change
pub comments: Vec<u64>,
pub comment_ids: Vec<u64>,

Copilot uses AI. Check for mistakes.
Comment on lines +139 to +154
let mut result: Vec<(AccountId, VerifiedContract)> = Vec::new();

for (k, v) in self.contracts.iter() {
if k.as_str()
.to_lowercase()
.replace(".testnet", "")
.replace(".near", "")
.contains(&key.to_lowercase())
{
result.push((k, v));
}
}

let pages: u64 = self.get_pages(result.len() as u64, limit as u64);
let filtered: Vec<(AccountId, ContractData)> = result
.into_iter()
.skip(from_index)
.take(limit)
.collect();
let filtered: Vec<(AccountId, VerifiedContract)> =
result.into_iter().skip(from_index).take(limit).collect();
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The search function iterates through all contracts before applying pagination. This is inefficient for large datasets because:

  1. It collects all matching results into a vector (line 139-150)
  2. Then applies skip/take pagination (line 154)

This means if there are 10,000 matching contracts but you only want page 1 with 10 results, it still processes all 10,000 entries.

Solution: Consider applying pagination during iteration:

let filtered: Vec<(AccountId, VerifiedContract)> = self.contracts
    .iter()
    .filter(|(k, _)| {
        k.as_str()
            .to_lowercase()
            .replace(".testnet", "")
            .replace(".near", "")
            .contains(&key.to_lowercase())
    })
    .skip(from_index)
    .take(limit)
    .collect();

Note: You'll need to count total matches separately for accurate page calculation.

Copilot uses AI. Check for mistakes.
Comment on lines +172 to 183
pub fn vote_contract(&mut self, account_id: AccountId, is_upvote: bool) {
let mut contract: VerifiedContract = self
.contracts
.get(&account_id)
.unwrap_or_else(|| panic!("Contract {} not found", account_id))
.into();

self.update_or_insert_vote(&mut contract.votes, is_upvote);

self.contracts.insert(&account_id, &contract);
log!("Vote updated for contract {}", account_id);
}
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The vote_contract function lacks test coverage for the error case where a user tries to vote on a non-existent contract. The function will panic with "Contract {} not found", but there's no test verifying this behavior.

Solution: Add a test case:

#[test]
#[should_panic(expected = "Contract")]
fn test_vote_nonexistent_contract() {
    let context = get_context(accounts(0));
    testing_env!(context.build());
    let mut contract = SourceScan::new();
    contract.vote_contract(accounts(1), true); // Should panic
}

Copilot uses AI. Check for mistakes.
Comment on lines +61 to +68
pub fn set_contract(
&mut self,
account_id: AccountId,
cid: String,
code_hash: String,
block_height: u64,
lang: String,
) {
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing input validation for string parameters in set_contract. The function accepts:

  • cid: Content identifier (could be empty or malformed)
  • code_hash: Hash of the contract code (should have specific format/length)
  • lang: Programming language (could be empty or invalid)

Without validation, invalid data could be stored, making the contract data unreliable.

Solution: Add validation:

require!(!cid.trim().is_empty(), "CID cannot be empty");
require!(!code_hash.trim().is_empty(), "Code hash cannot be empty");
require!(!lang.trim().is_empty(), "Language cannot be empty");
// Optionally validate format/length constraints

Copilot uses AI. Check for mistakes.
use std::hash::{Hash, Hasher};

#[near(serializers=[borsh, json])]
#[derive(PartialOrd, Eq, PartialEq, Clone)]
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The VoteType enum derives PartialOrd (line 7) but implements Ord manually (lines 45-55). Since Ord is a supertrait of PartialOrd, the derived PartialOrd implementation will be overridden by the blanket implementation impl<T: Ord> PartialOrd for T. However, having both the derive and manual implementation is confusing.

Solution: Remove PartialOrd from the derive macro on line 7, leaving only the manual Ord implementation (which automatically provides PartialOrd).

Suggested change
#[derive(PartialOrd, Eq, PartialEq, Clone)]
#[derive(Eq, PartialEq, Clone)]

Copilot uses AI. Check for mistakes.

[package.metadata.near.reproducible_build]
# docker image, descriptor of build environment
image = "sourcescan/cargo-near:0.17.0-rust-1.86.0"
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Docker image references Rust 1.86.0, but rust-toolchain.toml specifies Rust 1.85.0. This mismatch could lead to inconsistent build results between local development and Docker-based reproducible builds.

Solution: Update the image name to match the toolchain version (change 1.86.0 to 1.85.0), or update rust-toolchain.toml to use 1.86.0 if that's the intended version.

Suggested change
image = "sourcescan/cargo-near:0.17.0-rust-1.86.0"
image = "sourcescan/cargo-near:0.17.0-rust-1.85.0"

Copilot uses AI. Check for mistakes.
near-workspaces = { version = "0.9.0", default-features = false, features = ["install", "unstable"] }
tokio = { version = "1.12.0", features = ["full"] }
serde_json = "1"
near-sdk = { version = "5.1.0", features = ["unit-testing"] }
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dev-dependencies specify near-sdk = "5.1.0" while the main dependencies use near-sdk = "5.2.1". This version mismatch can cause compilation issues or unexpected behavior in tests, as the testing features might be compiled against a different version than the production code.

Solution: Update the dev-dependencies to use the same version as the main dependencies: near-sdk = { version = "5.2.1", features = ["unit-testing"] }

Suggested change
near-sdk = { version = "5.1.0", features = ["unit-testing"] }
near-sdk = { version = "5.2.1", features = ["unit-testing"] }

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,6 @@
{
"rust-analyzer.linkedProjects": [
"./Cargo.toml",
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The linkedProjects array contains duplicate entries of "./Cargo.toml". This is redundant and serves no purpose.

Solution: Remove one of the duplicate entries:

"rust-analyzer.linkedProjects": [
    "./Cargo.toml"
]
Suggested change
"./Cargo.toml",

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants