Block-Interval

礦工如何應對巨大的區塊時間?

  • October 13, 2017

鑑於:

  1. 根據白紙和黃紙,區塊的時間戳必須大於父區塊的時間戳
  2. 根據白皮書,區塊的時間戳可以在父區塊時間的 15 分鐘內

這是否意味著如果出現 14 分鐘的差異阻塞時間,

  1. 下一個獲勝的礦工必須要麼偽造時間戳,這可能會導致區塊鏈在未來越來越快地執行,
  2. 或者等到他的 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 來驗證時間戳。

引用自:https://ethereum.stackexchange.com/questions/5927