Block-Interval
礦工如何應對巨大的區塊時間?
鑑於:
- 根據白紙和黃紙,區塊的時間戳必須大於父區塊的時間戳。
- 根據白皮書,區塊的時間戳可以在父區塊時間的 15 分鐘內。
這是否意味著如果出現 14 分鐘的差異阻塞時間,
- 下一個獲勝的礦工必須要麼偽造時間戳,這可能會導致區塊鏈在未來越來越快地執行,
- 或者等到他的 Unix 時間趕上來。
這是真的?從經驗上講它從未發生過有什麼原因嗎?
概括
由礦工開采的區塊如果將他們的電腦時間設置在目前“實時”時間之前,他們的獲勝區塊將被其他乙太坊節點拒絕。乙太坊網路上的其他礦工將繼續探勘最新的有效區塊。
細節
根據程式碼,來自Github - Go Ethereum -consensus/ethash/consensus.go,第 220-284 行:
// verifyHeader checks whether a header conforms to the consensus rules of the // stock Ethereum ethash engine. // See YP section 4.3.4. "Block Header Validity" func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *types.Header, uncle bool, seal bool) error { // Ensure that the header's extra-data section is of a reasonable size if uint64(len(header.Extra)) > params.MaximumExtraDataSize { return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), params.MaximumExtraDataSize) } // Verify the header's timestamp if uncle { if header.Time.Cmp(math.MaxBig256) > 0 { return errLargeBlockTime } } else { if header.Time.Cmp(big.NewInt(time.Now().Unix())) > 0 { return consensus.ErrFutureBlock } } if header.Time.Cmp(parent.Time) <= 0 { return errZeroBlockTime } // Verify the block's difficulty based in it's timestamp and parent's difficulty expected := CalcDifficulty(chain.Config(), header.Time.Uint64(), parent) if expected.Cmp(header.Difficulty) != 0 { return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, expected) } // Verify that the gas limit is <= 2^63-1 if header.GasLimit.Cmp(math.MaxBig63) > 0 { return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, math.MaxBig63) } // Verify that the gasUsed is <= gasLimit if header.GasUsed.Cmp(header.GasLimit) > 0 { return fmt.Errorf("invalid gasUsed: have %v, gasLimit %v", header.GasUsed, header.GasLimit) } // Verify that the gas limit remains within allowed bounds diff := new(big.Int).Set(parent.GasLimit) diff = diff.Sub(diff, header.GasLimit) diff.Abs(diff) limit := new(big.Int).Set(parent.GasLimit) limit = limit.Div(limit, params.GasLimitBoundDivisor) if diff.Cmp(limit) >= 0 || header.GasLimit.Cmp(params.MinGasLimit) < 0 { return fmt.Errorf("invalid gas limit: have %v, want %v += %v", header.GasLimit, parent.GasLimit, limit) } // Verify that the block number is parent's +1 if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 { return consensus.ErrInvalidNumber } // Verify the engine specific seal securing the block if seal { if err := ethash.VerifySeal(chain, header); err != nil { return err } } // If all checks passed, validate any special fields for hard forks if err := misc.VerifyDAOHeaderExtraData(chain.Config(), header); err != nil { return err } if err := misc.VerifyForkHashes(chain.Config(), header, uncle); err != nil { return err } return nil }
當乙太坊節點接收到新塊時,將完成以下時間驗證:
if (newblock.header.time > thiscomputer.time) { error "block in the future" }
和
if (newblock.header.time <= newblock.parent.header.time) { error "timestamp equals parent's" }
錯誤消息來自Github - Go Ethereum -consensus/errors.go,第 28 行和Github - Go Ethereum -consensus/ethash/consensus.go,第 50 行。
奇偶校驗時間戳檢查
來自Github - Parity - ethcore/src/verification/verification.rs,第 197-209 行:
/// Check header parameters agains parent header. fn verify_parent(header: &Header, parent: &Header) -> Result<(), Error> { if !header.parent_hash.is_zero() && parent.hash() != header.parent_hash { return Err(From::from(BlockError::InvalidParentHash(Mismatch { expected: parent.hash(), found: header.parent_hash.clone() }))) } if header.timestamp <= parent.timestamp { return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp + 1), found: header.timestamp }))) } if header.number != parent.number + 1 { return Err(From::from(BlockError::InvalidNumber(Mismatch { expected: parent.number + 1, found: header.number }))); } Ok(()) }
因此,Parity 檢查區塊時間戳是否 > 父區塊時間戳,但不檢查區塊時間戳是否在未來。
來自Github - Parity - ethcore/src/verification/verification.rs,第 80-84 行:
/// Phase 3 verification. Check block information against parent and uncles. pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error> { // TODO: verify timestamp let parent = try!(bc.block_header(&header.parent_hash).ok_or_else(|| Error::from(BlockError::UnknownParent(header.parent_hash.clone())))); try!(verify_parent(&header, &parent));
有一個未完成的 TODO 來驗證時間戳。