use-ink/useink

Problem with timestamps in ink!

Closed this issue ยท 5 comments

I have governance platform written in ink!, where I can create poll with pollId, number of options, and with poll_start_time and poll_end_time. And in anytime I can create poll with correct timestamps in miliseconds.

So when poll is started I can't call vote function, and revert an error PollIsNotStarted.

Create poll function:

#[ink(message)]
        pub fn create_poll(
            &mut self,
            poll_id: String,
            number_of_options: u32,
            poll_start_timestamp: Timestamp,
            poll_end_timestamp: Timestamp,
        ) -> Result<(), Error> {

            let current_timestamp = self.env().block_timestamp();
            let poll_info = self.poll_data.get(&poll_id).unwrap_or_default();

            if poll_info.number_of_options != 0 {
                return Err(Error::PollIdAlreadyExists);
            }
            
            if number_of_options < 2 {
                return Err(Error::InvalidNumberOfOption)
            }

            if poll_start_timestamp < current_timestamp {
                return Err(Error::InvalidStartTimestamp)
            }

            if poll_end_timestamp <= poll_start_timestamp {
                return Err(Error::InvalidEndTimestamp)
            }

            let poll_info = PollInfo {
                number_of_options,
                poll_start_timestamp,
                poll_end_timestamp,
            };

            self.poll_data.insert(&poll_id, &poll_info);

            self.env().emit_event(PollCreated {
                poll_id: poll_id.clone(),
                number_of_options,
                poll_start_timestamp,
                poll_end_timestamp,
            });

            Ok(())
        }

Vote function:

#[ink(message)]
        pub fn vote(
            &mut self,
            poll_id: String,
            voting_option: u32,
            number_of_votes: Balance,
        ) -> Result<(), Error>{
            let caller = self.env().caller();

            if number_of_votes <= 0 {
                return Err(Error::InvalidNumberOfVotes)
            }

            let poll_info = self.poll_data.get(&poll_id).unwrap_or_default();
            let current_timestamp = self.env().block_timestamp();       

            if current_timestamp < poll_info.poll_start_timestamp {
                return Err(Error::PollIsNotStarted)
            }

            if current_timestamp > poll_info.poll_end_timestamp {
                return Err(Error::PollIsFinished);
            }
    
            if voting_option > poll_info.number_of_options{
                return Err(Error::InvalidNumberOfOption)
            }

            let mut voting_info = self.voting.get(&(poll_id.clone(), caller)).unwrap_or_default();

            if voting_info.voting_option == 0 {
                voting_info.voting_option = voting_option;                
            } else {
                if voting_info.voting_option != voting_option {
                    return Err(Error::VoteDenied)
                }
            }

            voting_info.number_of_votes += number_of_votes;    
                
            self.voting.insert(&(poll_id.clone(), caller), &voting_info); 

            self.env().emit_event(Voted {
                poll_id: poll_id.clone(),
                voter: caller,
                voting_option,
                number_of_votes,
            });           

            Ok(().into())


        }

I only can call this vote function if another poll is created. When is only one poll created I can't call vote function. Why is that?

Functions look good to me. However can you supply the whole contract or minimal working example for recreating the issue? That would really help.

Not sure if this is an issue with useink or does this issue only occur when you are interacting with your contract with useink functions? Have you interacted with this contract via https://contracts-ui.substrate.io/ for example? Does this ui encounter the same issue?

Functions look good to me. However can you supply the whole contract or minimal working example for recreating the issue? That would really help.

Not sure if this is an issue with useink or does this issue only occur when you are interacting with your contract with useink functions? Have you interacted with this contract via https://contracts-ui.substrate.io/ for example? Does this ui encounter the same issue?

Yeah, I interact with https://contracts-ui.substrate.io/, and still doesn't work. I tried on Rococo test network, but still same problem.
Here is the code, just take a look: https://github.com/JovanCBS/ceres-governace/tree/main/ceres_governance

Any thoughts? @peetzweg

Any thoughts? @peetzweg

Thanks for pinging again. Just gave it a try and I might know which issue you are running into.

Your contract relies on the timestamp of the current block via self.env().block_timestamp();.

When running a localnode, the node does only produce new blocks when transactions come in. This block_timestamp gets updated on a block by block basis. So if your node does not produce new blocks this timestamp gets not updated. Causing this behavior, that your proposal does not start before you created another one (aka creating new valid transactions for the node to include in blocks, creating new blocks with new timestamps).

The contracts-ui dapp does a dry-run of the transaction, however this does it on the basis of the most recent block, which has a timestamp which is in the past, preventing you submitting the actual transaction. Although the actual transaction would succeed as it would be included in a block with an updated block_timestamp. ๐Ÿค”

I was able to confirm it's working as intended when deploying it on rococo/contracts parachain. Agree this is not very workable. IIRC there is an option to make the localnode produce empty blocks automatically, thereby advancing the block_timestamp. Can't find it right now, will update this comment once I know more.

Hth, @JovanCBS

Rococo Faucet: https://paritytech.github.io/polkadot-testnet-faucet/

Screenshot 2023-09-18 at 14 07 07

Yeah man, that make sense, I just try this on Rococo, and work just fine.
Thanks for help @peetzweg