func (c *ecrecover) Run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
const ecRecoverInputLength = 128
input = common.RightPadBytes(input, ecRecoverInputLength)
// "input" is (hash, v, r, s), each 32 bytes
// but for ecrecover we want (r, s, v)
r := new(big.Int).SetBytes(input[64:96])
s := new(big.Int).SetBytes(input[96:128])
v := input[63] - 27
// tighter sig s values input homestead only apply to tx sigs
if !allZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) {
return nil, nil
}
// We must make sure not to modify the 'input', so placing the 'v' along with
// the signature needs to be done on a new allocation
sig := make([]byte, 65)
copy(sig, input[64:128])
sig[64] = v
// v needs to be at the end for libsecp256k1
pubKey, err := crypto.Ecrecover(input[:32], sig)
// make sure the public key is a valid one
if err != nil {
return nil, nil
}
// the first byte of pubkey is bitcoin heritage
return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32), nil
}
func (c *transfer) Run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
caller := contract.CallerAddress
atlasGoldAddress, err := evm.Context.GetRegisteredAddress(evm, params2.GoldTokenRegistryId)
if err != nil {
return nil, err
}
// input is comprised of 3 arguments:
// from: 32 bytes representing the address of the sender
// to: 32 bytes representing the address of the recipient
// value: 32 bytes, a 256 bit integer representing the amount of Atlas Gold to transfer
// 3 arguments x 32 bytes each = 96 bytes total input
if len(input) < 96 {
return nil, ErrInputLength
}
if caller != atlasGoldAddress {
return nil, fmt.Errorf("Unable to call transfer from unpermissioned address")
}
from := common.BytesToAddress(input[0:32])
to := common.BytesToAddress(input[32:64])
var parsed bool
value, parsed := math.ParseBig256(hexutil.Encode(input[64:96]))
if !parsed {
return nil, fmt.Errorf("Error parsing transfer: unable to parse value from " + hexutil.Encode(input[64:96]))
}
if from == params2.ZeroAddress {
// Mint case: Create cGLD out of thin air
evm.StateDB.AddBalance(to, value)
} else {
// Fail if we're trying to transfer more than the available balance
if !evm.Context.CanTransfer(evm.StateDB, from, value) {
return nil, ErrInsufficientBalance
}
//evm.Context.Transfer(evm, from, to, value)
}
return input, err
}
fractionMulExp
地址 0x00000000000000000000000000000000000000fc
計算 a * (b ^ exponent) 到精度的小數位,其中 a 和 b 是分數
func (c *fractionMulExp) Run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
// input is comprised of 6 arguments:
// aNumerator: 32 bytes, 256 bit integer, numerator for the first fraction (a)
// aDenominator: 32 bytes, 256 bit integer, denominator for the first fraction (a)
// bNumerator: 32 bytes, 256 bit integer, numerator for the second fraction (b)
// bDenominator: 32 bytes, 256 bit integer, denominator for the second fraction (b)
// exponent: 32 bytes, 256 bit integer, exponent to raise the second fraction (b) to
// decimals: 32 bytes, 256 bit integer, places of precision
//
// 6 args x 32 bytes each = 192 bytes total input length
if len(input) < 192 {
return nil, ErrInputLength
}
parseErrorStr := "Error parsing input: unable to parse %s value from %s"
aNumerator, parsed := math.ParseBig256(hexutil.Encode(input[0:32]))
if !parsed {
return nil, fmt.Errorf(parseErrorStr, "aNumerator", hexutil.Encode(input[0:32]))
}
aDenominator, parsed := math.ParseBig256(hexutil.Encode(input[32:64]))
if !parsed {
return nil, fmt.Errorf(parseErrorStr, "aDenominator", hexutil.Encode(input[32:64]))
}
bNumerator, parsed := math.ParseBig256(hexutil.Encode(input[64:96]))
if !parsed {
return nil, fmt.Errorf(parseErrorStr, "bNumerator", hexutil.Encode(input[64:96]))
}
bDenominator, parsed := math.ParseBig256(hexutil.Encode(input[96:128]))
if !parsed {
return nil, fmt.Errorf(parseErrorStr, "bDenominator", hexutil.Encode(input[96:128]))
}
exponent, parsed := math.ParseBig256(hexutil.Encode(input[128:160]))
if !parsed {
return nil, fmt.Errorf(parseErrorStr, "exponent", hexutil.Encode(input[128:160]))
}
decimals, parsed := math.ParseBig256(hexutil.Encode(input[160:192]))
if !parsed {
return nil, fmt.Errorf(parseErrorStr, "decimals", hexutil.Encode(input[160:192]))
}
// Handle passing of zero denominators
if aDenominator == big.NewInt(0) || bDenominator == big.NewInt(0) {
return nil, fmt.Errorf("Input Error: Denominator of zero provided!")
}
if !decimals.IsInt64() || !exponent.IsInt64() || max(decimals.Int64(), exponent.Int64()) > 100000 {
return nil, fmt.Errorf("Input Error: Decimals or exponent too large")
}
numeratorExp := new(big.Int).Mul(aNumerator, new(big.Int).Exp(bNumerator, exponent, nil))
denominatorExp := new(big.Int).Mul(aDenominator, new(big.Int).Exp(bDenominator, exponent, nil))
decimalAdjustment := new(big.Int).Exp(big.NewInt(10), decimals, nil) //10^18
numeratorDecimalAdjusted := new(big.Int).Div(new(big.Int).Mul(numeratorExp, decimalAdjustment), denominatorExp).Bytes()
denominatorDecimalAdjusted := decimalAdjustment.Bytes()
numeratorPadded := common.LeftPadBytes(numeratorDecimalAdjusted, 32)
denominatorPadded := common.LeftPadBytes(denominatorDecimalAdjusted, 32)
return append(numeratorPadded, denominatorPadded...), nil
}
佔有證明
地址 0x00000000000000000000000000000000000000fb
驗證validator的地址、publicKey、g1publickey、signature
func (c *proofOfPossession) Run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
// input is comprised of 3 arguments:
// address: 20 bytes, an address used to generate the proof-of-possession
// publicKey: 129 bytes, representing the public key (defined as a const in bls package)
// G1PUBLICKEYBYTES: 129 bytes, representing the bls public key (defined as a const in bls package)
// signature: 64 bytes, representing the signature on `address` (defined as a const in bls package)
// the total length of input required is the sum of these constants
if len(input) != common.AddressLength+blscrypto.PUBLICKEYBYTES+blscrypto.G1PUBLICKEYBYTES+blscrypto.SIGNATUREBYTES {
return nil, ErrInputLength
}
addressBytes := input[:common.AddressLength]
publicKeyBytes := input[common.AddressLength : common.AddressLength+blscrypto.PUBLICKEYBYTES]
publicKey, err := bls.UnmarshalPk(publicKeyBytes)
if err != nil {
return nil, err
}
apk := bls.NewApk(publicKey)
signatureBytes := input[common.AddressLength+blscrypto.PUBLICKEYBYTES+blscrypto.G1PUBLICKEYBYTES : common.AddressLength+blscrypto.PUBLICKEYBYTES+blscrypto.G1PUBLICKEYBYTES+blscrypto.SIGNATUREBYTES]
signature := bls.Signature{}
signature.Unmarshal(signatureBytes)
err = bls.Verify(apk, addressBytes, &signature)
if err != nil {
return nil, err
}
G1 := input[common.AddressLength+blscrypto.PUBLICKEYBYTES : common.AddressLength+blscrypto.PUBLICKEYBYTES+blscrypto.G1PUBLICKEYBYTES]
err = bls.VerifyG1Pk(G1, publicKeyBytes)
if err != nil {
return nil, err
}
return true32Byte, nil
}
func (c *getValidator) Run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
// input is comprised of two arguments:
// index: 32 byte integer representing the index of the validator to get
// blockNumber: 32 byte integer representing the block number to access
if len(input) < 64 {
return nil, ErrInputLength
}
index := new(big.Int).SetBytes(input[0:32])
blockNumber := new(big.Int).SetBytes(input[32:64])
if blockNumber.Cmp(common.Big0) == 0 {
// Validator set for the genesis block is empty, so any index is out of bounds.
return nil, ErrValidatorsOutOfBounds
}
if blockNumber.Cmp(evm.Context.BlockNumber) > 0 {
return nil, ErrBlockNumberOutOfBounds
}
// Note: Passing empty hash as here as it is an extra expense and the hash is not actually used.
validators := evm.Context.GetValidators(new(big.Int).Sub(blockNumber, common.Big1), common.Hash{})
// Ensure index, which is guaranteed to be non-negative, is valid.
if index.Cmp(big.NewInt(int64(len(validators)))) >= 0 {
return nil, ErrValidatorsOutOfBounds
}
validatorAddress := validators[index.Uint64()].Address()
addressBytes := common.LeftPadBytes(validatorAddress[:], 32)
return addressBytes, nil
}
func (c *numberValidators) Run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
// input is comprised of a single argument:
// blockNumber: 32 byte integer representing the block number to access
if len(input) < 32 {
return nil, ErrInputLength
}
blockNumber := new(big.Int).SetBytes(input[0:32])
if blockNumber.Cmp(common.Big0) == 0 {
// Genesis validator set is empty. Return 0.
return make([]byte, 32), nil
}
if blockNumber.Cmp(evm.Context.BlockNumber) > 0 {
return nil, ErrBlockNumberOutOfBounds
}
// Note: Passing empty hash as here as it is an extra expense and the hash is not actually used.
validators := evm.Context.GetValidators(new(big.Int).Sub(blockNumber, common.Big1), common.Hash{})
numberValidators := big.NewInt(int64(len(validators))).Bytes()
numberValidatorsBytes := common.LeftPadBytes(numberValidators[:], 32)
return numberValidatorsBytes, nil
}
func (c *getParentSealBitmap) Run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
// input is comprised of a single argument:
// blockNumber: 32 byte integer representing the block number to access
if len(input) < 32 {
return nil, ErrInputLength
}
blockNumber := new(big.Int).SetBytes(input[0:32])
// Ensure the request is for information from a previously sealed block.
if blockNumber.Cmp(common.Big0) == 0 || blockNumber.Cmp(evm.Context.BlockNumber) > 0 {
return nil, ErrBlockNumberOutOfBounds
}
// Ensure the request is for a sufficiently recent block to limit state expansion.
historyLimit := new(big.Int).SetUint64(evm.Context.EpochSize * 4)
if blockNumber.Cmp(new(big.Int).Sub(evm.Context.BlockNumber, historyLimit)) <= 0 {
return nil, ErrBlockNumberOutOfBounds
}
header := evm.Context.GetHeaderByNumber(blockNumber.Uint64())
if header == nil {
log.Error("Unexpected failure to retrieve block in getParentSealBitmap precompile", "blockNumber", blockNumber)
return nil, ErrUnexpected
}
extra, err := types.ExtractIstanbulExtra(header)
if err != nil {
log.Error("Header without Istanbul extra data encountered in getParentSealBitmap precompile", "blockNumber", blockNumber, "err", err)
return nil, ErrEngineIncompatible
}
return common.LeftPadBytes(extra.ParentAggregatedSeal.Bitmap.Bytes()[:], 32), nil
}
func (c *getVerifiedSealBitmap) Run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
// input is comprised of a single argument:
// header: rlp encoded block header
var header types.Header
if err := rlp.DecodeBytes(input, &header); err != nil {
return nil, ErrInputDecode
}
// Verify the seal against the engine rules.
if !evm.Context.VerifySeal(&header) {
return nil, ErrInputVerification
}
// Extract the verified seal from the header.
extra, err := types.ExtractIstanbulExtra(&header)
if err != nil {
log.Error("Header without Istanbul extra data encountered in getVerifiedSealBitmap precompile", "extraData", header.Extra, "err", err)
// Seal verified by a non-Istanbul engine. Return an error.
return nil, ErrEngineIncompatible
}
return common.LeftPadBytes(extra.AggregatedSeal.Bitmap.Bytes()[:], 32), nil
}