Sifchain / sifnode

SifNode - The future of Defi
Other
109 stars 118 forks source link

FC4-04 | Possible Inconsistencies Between Sifchain States And Smart Contract States #3153

Open Brando753 opened 2 years ago

Brando753 commented 2 years ago

Let's huddle to discuss the best way to resolve this issue. @banshee @smartyalgo @Brando753

Description

Events emitted by the smart contracts will be synced to the Sifchain, and events on the Sifchain will also be synced to the smart contracts after collecting enough validator signatures, so smart contract states, such as the power of validators, consensus rate, and blacklist, should be consistent with Sifchain chain states after syncing. However, due to the latency caused by the syncing process, the smart contract states and the Sifchain states are not always consistent.

For example, the relayer checks if a event has collected enough validator signatures on the Sifchain:

func (k Keeper) processCompletion(ctx sdk.Context, networkDescriptor types.NetworkDescriptor, prophecy types.Prophecy) types.Prophecy {
    whiteList := k.GetOracleWhiteList(ctx, types.NewNetworkIdentity(networkDescriptor))
    voteRate := whiteList.GetPowerRatio(prophecy.ClaimValidators)
    var consensusNeeded float64
    consensusNeededUint, err := k.GetConsensusNeeded(ctx, types.NewNetworkIdentity(networkDescriptor))

    if err != nil {
        consensusNeeded = k.consensusNeeded
    } else {
        consensusNeeded = float64(consensusNeededUint) / 100.0
    }

    if voteRate >= consensusNeeded {
        prophecy.Status = types.StatusText_STATUS_TEXT_SUCCESS
    }

    instrumentation.PeggyCheckpoint(ctx.Logger(), instrumentation.ProcessCompletion, "prophecy", zap.Reflect("prophecy", prophecy))

    return prophecy
}

After the event is submitted to the Ethereum chain, the signatures will be checked again, include the validity of the signer's identity, the legitimacy of the signature and the consensus rate:

function getSignedPowerAndFindDup(SignatureData[] calldata _validators, bytes32 hashDigest)
    private view returns (uint256 pow){
    uint256 validatorLength = _validators.length; 
    for (uint256 i; i < validatorLength; ) {
      SignatureData calldata validator = _validators[i];
      require(isActiveValidator(validator.signer), "INV_SIGNER");
      require(
        verifySignature(validator.signer, hashDigest, validator._v, validator._r, validator._s),
        "INV_SIG");

      unchecked {pow += getValidatorPower(validator.signer);}

      for (uint256 j = i + 1; j < validatorLength; ) {
        require(validator.signer != _validators[j].signer, "DUP_SIGNER");
        unchecked {
          ++j;
        }
      }
      unchecked {
        ++i;
      }
    }
  }
function getProphecyStatus(uint256 signedPower) public view returns (bool) {
    // Prophecy must reach total signed power % threshold in order to pass consensus
    uint256 prophecyPowerThreshold = totalPower * consensusThreshold;
    // consensusThreshold is a decimal multiplied by 100, so signedPower must also be multiplied by 100
    uint256 prophecyPowerCurrent = signedPower * 100;
    bool hasReachedThreshold = prophecyPowerCurrent >= prophecyPowerThreshold;
    return hasReachedThreshold;
  }

However, it is possible that the state of a validator is changed, for example, a new validator has been added to the validatorWhiteList on the Sifchain, but the change has not been synced to the Ethereum chain. Therefore, the signature check might be passed on the Sifchain but fail the checkup on the CosmosBridge contract.

Recommendation

Recommend checking if the corner cases caused by the aforementioned inconsistencies are acceptable, if it is not, modifying the syncing mechanism to ensure consistency.

pandaring2you commented 2 years ago

To discuss with @Brando753

smartyalgo commented 2 years ago

The solution to this is to ensure we can pause import on the evm smart contract, and export on the sifnoded side. Currently smart contract supports pausing, but sifnoded doesn't. See #2445