Dado que:
¿Eso implicaría que si ocurre un tiempo de bloqueo diferencial de 14 min,
¿Es esto cierto? ¿Hay alguna razón por la que empíricamente nunca sucedió ?
Un bloque extraído por un minero que establece el tiempo de su computadora por delante del tiempo "real" actual tendrá su bloque ganador rechazado por otros nodos de Ethereum. Otros mineros en la red Ethereum continuarán extrayendo en el último bloque válido.
Según el código, de Github - Go Ethereum - consenso/ethash/consensus.go, líneas 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
}
Las siguientes validaciones de tiempo se realizan cuando un nodo Ethereum recibe un nuevo bloque:
if (newblock.header.time > thiscomputer.time) {
error "block in the future"
}
y
if (newblock.header.time <= newblock.parent.header.time) {
error "timestamp equals parent's"
}
Los mensajes de error son de Github - Go Ethereum - consenso/errors.go, línea 28 y Github - Go Ethereum - consenso/ethash/consensus.go, línea 50 .
De Github - Parity - ethcore/src/verification/verification.rs, líneas 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(())
}
Por lo tanto, Parity verifica que la marca de tiempo del bloque sea > la marca de tiempo del bloque principal, pero no verifica si la marca de tiempo del bloque está en el futuro.
Desde Github - Parity - ethcore/src/verification/verification.rs, líneas 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));
Hay una TODO pendiente para verificar la marca de tiempo.
@Roland Kofler
, agregué el código relevante para Parity al final de mi respuesta.Si un minero M ve un bloque B con una marca de tiempo en un futuro lejano, esto es lo que probablemente haría: en lugar de construir sobre B, publicaría su propio bloque C con una marca de tiempo más precisa. Al hacer esto, es probable que M sea recompensado, ya que es probable que otros se basen en C en lugar de B.
Como se menciona en la pregunta, para construir sobre el bloque B, un minero, como M, tendría que usar una marca de tiempo falsa (ya que la marca de tiempo de un bloque debe ser más grande que la del padre). ¿Por qué M construiría sobre B, cuando hacerlo requerirá que otros mineros usen una marca de tiempo falsa para construir sobre el bloque de M? Hay más beneficios para M si publica un bloque C con una marca de tiempo más precisa.
La estrategia de M se ve favorecida por el hecho de que, de forma predeterminada, todos los nodos de Ethereum se coordinan en torno a la hora correcta, por lo que M tiene una idea de si debe construir sobre B o publicar su propio C.
Para conectarse con la respuesta de @BokkyPooBah, cuando un nodo ve B, el nodo rechaza B con BlockFutureErr para que no produzca un bloque no válido X (donde B.timestamp >= X.timestamp) por protocolo . Pero tenga en cuenta que no hay nada en el protocolo que diga algo sobre la invalidez de que un bloque tenga una marca de tiempo en un futuro lejano.
ética