Skip to content

Commit

Permalink
Add GetCoinbase precompiled contract (ethereum#58)
Browse files Browse the repository at this point in the history
* Modify geth for single commit verification with GetMinerOf precompiled contract

* Fix references

* Add comment for empty address behavior

* Rename to GetCoinbase

* Fix comment

* Rename to RequestIndex
  • Loading branch information
nambrot authored Oct 24, 2018
1 parent 6cdda73 commit 9568b4a
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 14 deletions.
3 changes: 1 addition & 2 deletions abe/abe.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func createVerificationMessage(request types.VerificationRequest, verificationRe
if err != nil {
return "", err
}
return fmt.Sprintf("Celo verification code: %s:%d:%s", base64.URLEncoding.EncodeToString(signature), request.VerificationIndex, base64.URLEncoding.EncodeToString(verificationRewardsAddress.Bytes())), nil
return fmt.Sprintf("Celo verification code: %s:%d:%d:%s", base64.URLEncoding.EncodeToString(signature), request.RequestIndex, request.VerificationIndex, base64.URLEncoding.EncodeToString(verificationRewardsAddress.Bytes())), nil
}

func sendSms(phoneNumber string, message string, account common.Address, verificationServiceURL string) error {
Expand Down Expand Up @@ -91,7 +91,6 @@ func SendVerificationMessages(receipts []*types.Receipt, block *types.Block, coi
log.Error("[Celo] Failed to decrypt phone number", "err", err)
continue
}
log.Debug(fmt.Sprintf("[Celo] Phone number %s requesting verification", phoneNumber))

message, err := createVerificationMessage(request, verificationRewardsAddress, account, wallet)
if err != nil {
Expand Down
29 changes: 29 additions & 0 deletions core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author
CanTransfer: CanTransfer,
Transfer: Transfer,
GetHash: GetHashFn(header, chain),
GetCoinbase: GetCoinbaseFn(header, chain),
Origin: msg.From(),
Coinbase: beneficiary,
BlockNumber: new(big.Int).Set(header.Number),
Expand Down Expand Up @@ -84,6 +85,34 @@ func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash
}
}

// GetCoinbaseFn returns a GetCoinbaseFunc which retrieves the coinbase by block number
func GetCoinbaseFn(ref *types.Header, chain ChainContext) func(n uint64) common.Address {
var cache map[uint64]common.Address

return func(n uint64) common.Address {
// If there's no address cache yet, make one
if cache == nil {
cache = map[uint64]common.Address{
ref.Number.Uint64(): ref.Coinbase,
}
}
// Try to fulfill the request from the cache
if address, ok := cache[n]; ok {
return address
}
// Not cached, iterate the blocks and cache the addresses
for header := chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) {
cache[header.Number.Uint64()] = header.Coinbase
if n == header.Number.Uint64() {
return header.Coinbase
}
}

// Like GetHashFn we'll just return an empty address if we can't find it
return common.Address{}
}
}

// CanTransfer checks whether there are enough funds in the address' account to make a transfer.
// This does not take the necessary gas in to account to make the transfer valid.
func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool {
Expand Down
31 changes: 19 additions & 12 deletions core/types/receipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ const (
// VerificationRequest represents a request for verification in the Celo ABE protocol.
type VerificationRequest struct {
PhoneHash common.Hash
CodeHash common.Hash
Account common.Address
RequestIndex *big.Int
VerificationIndex *big.Int
CodeHash common.Hash
Verifier common.Address
EncryptedPhone hexutil.Bytes
}
Expand Down Expand Up @@ -111,25 +112,31 @@ func NewReceipt(root []byte, failed bool, cumulativeGasUsed uint64) *Receipt {
// Decode a VerificationRequest from raw input bytes.
// Input is expected to be encoded in the following manner:
// input[0:32]: bytes32 phoneHash
// input[32:64]: address account
// input[64:96]: bytes32 verificationIndex
// input[96:128]: bytes32 codeHash
// input[128:160]: address verifier
// input[160:] bytes encryptedPhone
// input[32:64]: bytes32 codeHash
// input[64:96]: address account
// input[96:128]: bytes32 requestIndex
// input[128:160]: bytes32 verificationIndex
// input[160:192]: address verifier
// input[192:]: bytes encryptedPhone
func DecodeVerificationRequest(input []byte) (VerificationRequest, error) {
var v VerificationRequest
v.PhoneHash = common.BytesToHash(input[0:32])
v.Account = common.BytesToAddress(input[32:64])
v.Account = common.BytesToAddress(input[64:96])
var parsed bool
v.VerificationIndex, parsed = math.ParseBig256(hexutil.Encode(input[64:96]))
v.RequestIndex, parsed = math.ParseBig256(hexutil.Encode(input[96:128]))
if !parsed {
return v, fmt.Errorf("Error parsing VerificationRequest: unable to parse VerificationIndex from " + hexutil.Encode(input[64:96]))
return v, fmt.Errorf("Error parsing VerificationRequest: unable to parse RequestIndex from " + hexutil.Encode(input[96:128]))
}
v.CodeHash = common.BytesToHash(input[96:128])
v.Verifier = common.BytesToAddress(input[128:160])
v.VerificationIndex, parsed = math.ParseBig256(hexutil.Encode(input[128:160]))
if !parsed {
return v, fmt.Errorf("Error parsing VerificationRequest: unable to parse VerificationIndex from " + hexutil.Encode(input[128:160]))
}

v.CodeHash = common.BytesToHash(input[32:64])
v.Verifier = common.BytesToAddress(input[160:192])

// TODO(asa): Consider validating the length of EncryptedPhone
v.EncryptedPhone = input[160:]
v.EncryptedPhone = input[192:]
return v, nil
}

Expand Down
19 changes: 19 additions & 0 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{

var CeloPrecompiledContractsAddressOffset = byte(0xff)
var requestVerificationAddress = common.BytesToAddress(append([]byte{0}, CeloPrecompiledContractsAddressOffset))
var getCoinbaseAddress = common.BytesToAddress(append([]byte{0}, (CeloPrecompiledContractsAddressOffset - 1)))
var transferAddress = common.BytesToAddress(append([]byte{0}, (CeloPrecompiledContractsAddressOffset - 2)))

// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
Expand All @@ -68,6 +69,7 @@ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{

// Celo Precompiled Contracts
requestVerificationAddress: &requestVerification{},
getCoinbaseAddress: &getCoinbase{},
transferAddress: &transfer{},
}

Expand Down Expand Up @@ -391,6 +393,23 @@ func (c *requestVerification) Run(input []byte, evm *EVM) ([]byte, error) {
}
}

type getCoinbase struct{}

func (c *getCoinbase) RequiredGas(input []byte) uint64 {
return params.GetCoinbaseGas
}

func (c *getCoinbase) Run(input []byte, evm *EVM) ([]byte, error) {
var blockNumber, parsingSuccess = math.ParseBig256(hexutil.Encode(input[0:32]))

if !parsingSuccess {
return input, fmt.Errorf("Error parsing block number:" + hexutil.Encode(input[0:32]))
}

var coinbase = evm.Context.GetCoinbase(blockNumber.Uint64())
return coinbase.Bytes(), nil
}

// Native transfer contract to make Celo Gold ERC20 compatible.
type transfer struct{}

Expand Down
5 changes: 5 additions & 0 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ type (
// GetHashFunc returns the nth block hash in the blockchain
// and is used by the BLOCKHASH EVM op code.
GetHashFunc func(uint64) common.Hash
// GetCoinbaseFunc returns the nth block coinbase in the blockchain
// and is used by the Celo Precompiled Contract.
GetCoinbaseFunc func(uint64) common.Address
)

// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
Expand Down Expand Up @@ -78,6 +81,8 @@ type Context struct {
Transfer TransferFunc
// GetHash returns the hash corresponding to n
GetHash GetHashFunc
// GetCoinbase returns the coinbase corresponding to n
GetCoinbase GetCoinbaseFunc

// Message information
Origin common.Address // Provides information for ORIGIN
Expand Down
1 change: 1 addition & 0 deletions params/protocol_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const (
// Celo precompiled contracts
// TODO(asa): Figure out what the actual gas cost of this contract should be.
VerificationRequestGas uint64 = 3000 // Per-message price for sending an SMS. Not an accurate representation of the real cost of sending an SMS.
GetCoinbaseGas uint64 = 20 // Equivalent to the cost of the BLOCKHASH op
)

var (
Expand Down

0 comments on commit 9568b4a

Please sign in to comment.