7

I have a sorted linked list that contains around 1000 items. When I receive a new item my goal is to push the item to the list keeping the sorted order. So if I receive very small value, I am required to iterate all the list to find the tail of the list. I have suggested that I could retreive the index via constant function and my transaction function could use the returned index value to push the item to correct location without spending gas to iterate the list.

My goal is to follow this guide (https://ethereum.stackexchange.com/a/13855/4575) to call a constant function and submit its return value into a transaction function.

getIndex() => constant 
setArray() => transaction

setArray( getIndex() );

The question emerges that: when I call a constant function on my client node is it possible to check that does my client node's block number is the best block number or is it behind. If it is behind, constant function may return wrong information.

For example blockchain's best block is 100. But my node is in currently at blockNumber 90 (basically behind of the blockchain). So when the client node get the index of the list up to first 90 blocks and miss items generated on the remaining 10 blocks.

[Q] Is it possible to check that does client's node's block number matches with the blockchain's best which is the latest block number?

As you can see on the example image, block number on the client nodes may vary. Best block number is 1,002,312 but block number is 1,002,304 on node on the top. But sometimes all nodes are on the latest block number. So it is hard to trust to node's behaviour.

enter image description here

Following answer seems working:

web3.eth.syncing;
sync.highestBlock

But returned highestBlock number still seems few blocks number smaller than on my best block number on my private chain. Is it a normal case?

0

3 Answers 3

4
+50

Ethereum is a probabilistic system.

In my opinion, there is just no way to be certain that one is looking at the latest block that will ultimately make it into the longest chain with vanishingly small improbability that a chain reorganization will rearrange things. Therefore, I don't think reliance on a client witness is good way to inform a sorting process.

I'm a strong believer in the principle that a Smart Contract must safeguard the integrity of the internal data storage. If the data must be accessible in sorted order (not necessarily an on-chain concern), then the order of the data lies within the scope of "guaranteed internal integrity".

By that rationale, reliance on correct information from the call() you describe and the need for it to be current must go. It's an unacceptable external dependency and probably not satisfactorily solvable.

Consider three general approaches

  • Insert "Bob"
  • Insert "Bob" after "Alice"
  • Insert "Bob" near "Alice"

The first may call for considerable depth in the internal search and will not scale well. The second approach depends on reliable information from outside; reliability we probably can't achieve. The third approach relies on a hint for gas efficiency, but leaves it to the contract to make the final, correct decision.

"Near" is basically a head start on the search process. Importantly, the contract will complete the search and reach it's own conclusions about where & how to insert "Bob" given the current state of the ordered list. Any list in any state in any block on any chain would have to be correctly ordered, owing to not depending on precise external guidance.

In summary:

I would first consider if the sort necessarily really needs to be on the chain.

If the sort is unavoidable, then organize a sorted linked-list or similar index scheme in the contract. The contract alone should determine correct insertion points. A "hint" may reduce internal searching needed to do that, thereby reducing gas cost and helping ensure the process will work on a list of any size.

Hope it helps.

5
  • Same problem but with different scenario.Imagine on my node I purchased an item. As a timestamp I want to use highest block number.Node will assign the timestamp as the blk.num but his local block.number might be smaller than the highest block number. So timestamp of purchase might be seen earlier since node's blk.num is behind. In this case, my external algorithm isn't able to trust the timestamp as block number information as purchase time. Basically each node’s timestamp as block.number will be different from each other at time T, where timestamp of blk.num isn't trustable.@Rob Hitchens
    – alper
    Commented Apr 25, 2017 at 12:44
  • 1
    You seem to be thinking about the node acting independently and having special powers over the transaction. It does not. The node used to submit the transaction to the network is merely a link in a chain of communication. It has no special privileges or special influence over the outcome of the transaction. The block.number cannot be wrong. It will match the block.number when the transaction is mined by the network. Since miners have some latitude about when to include a transaction, it's only loosely coupled to submission time, but it is inarguably correct in terms of what it represents. Commented Apr 25, 2017 at 19:23
  • Independent from a transaction, I want just node to obtain the highest block number from the blockchain instead of his local block number. web3.eth.syncing; does not work all the time and when it does not return valid information, blockchain's latest number may also change until a valid information returned. Ethereum is a probabilistic system as you said I cant wait exact time respond from the network I guess. sorry for too much questions... @RobHitchens
    – alper
    Commented Apr 26, 2017 at 7:00
  • Thanks for this post. It was useful in that it indirectly led me to another conclusion, and you may find my little debugging story interesting. I wrote a tweet thread on it here, which I found to be incorrect, then a follow-up tweet thread here. Life as a blockchain developer dealing with heisenbugs in production! 😉
    – Neo
    Commented Dec 12, 2021 at 12:26
  • Not sure if it's helpful or adds another layer of confusion. The OP is about an observer and assuming things about the state when inserting a transaction into the chain. The observer will always only know what they know and will not know what they don't know. And, the state will possibly change before a transaction is mined. On-chain, in contracts the time is always "now" and the state is always current. This holds in chains of contracts calling each other. There is a state and things happen in the context of that state, but observers' knowledge always lags. Commented Dec 13, 2021 at 19:33
2

Yes it is possible to check whethers block number matches with the blockchain's best(latest) block number.

The steps would be

  1. Query a public blockchain API to get latest block number
  2. Check against clients block no.

The submitting transaction part requires some changes in the core/api layer.

8
  • How could I query a public blockchain API? Through a contract's function, if I call a function which returns block.number as I understand it should return latest block number. I didn't get what you meant by "changes in the core/api layer."@niksmac
    – alper
    Commented Apr 3, 2017 at 15:51
  • @Avatar etherscan.io/blocks here is a public information board, this page shows the highest(best) block from its perspective. Commented Apr 5, 2017 at 3:56
  • I am working on a private chain so etherscan.io/blocks link won't help me. I do also prefer to obtain the value from a function call, without looking into a gui. @Yuanfei Zhu
    – alper
    Commented Apr 17, 2017 at 10:22
  • could public blockchain API be constant or non-constant function? Since constant will read from its local data it won't help. @niksmac
    – alper
    Commented Apr 17, 2017 at 12:36
  • @Avatar how that could be constant? thats the number of latest block right? Yuanfei Zhu's info is correct.
    – niksmac
    Commented Apr 17, 2017 at 16:13
2

The RPC API got your back.

Just use this function to check your and the client's latest block. Depending on how much you want to trust the client, you can compare the values on the client's side or make sure it gets transfered back to you without manipulation.

Function for getting the latest block:

web3.currentProvider.sendAsync({
  method: "eth_blockNumber",
  params: [],
  jsonrpc: "2.0",
  id: 83
} function (error, result) {...})

More details on the JSON RPC API and how you can use it in many different ways (with curl, for example): Here

You can use curl, by the way, to check the clients current block remotely, if it's node and firewall settings allow the connection.

Of course, don't forget to turn the result to a decimal number, parseInt(value, 16).

You can find an example of how to implement such web3 functions here.

2
  • I have tried your suggestion curl --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":83}' -X POST localhost:8545 This also returns the node's current block number, not the highest achieved block number. Obtaining client's block number is not the problem, but it may behind of the highest block number. @NikitaFuchs
    – alper
    Commented Apr 17, 2017 at 12:26
  • 1
    Just do this with a node you trust to be at the latest blocknumber, then you have something to compare with. That is what I meant to say in my original answer.
    – n1cK
    Commented Apr 17, 2017 at 18:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.