Skip to content

Commit

Permalink
Merge pull request #3033 from smartcontractkit/release/0.8.6-rc1
Browse files Browse the repository at this point in the history
Release/0.8.6 rc1
  • Loading branch information
tyrion70 authored Jun 11, 2020
2 parents 2eaf07c + 206ba8d commit 9e8254c
Show file tree
Hide file tree
Showing 92 changed files with 1,933 additions and 3,087 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ node_modules/
tmp/
.pnp
.pnp.js
tools/bin/abigen

/chainlink
core/chainlink
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.8.6] - 2020-06-08

### Added

- The node now logs the eth client RPC calls
- More reliable Ethereum block header tracking
- Limit the amount of an HTTP response body that the node will read
- Make Aggregator contract interface viewable
- More resilient handling of chain reorganizations

## [0.8.5] - 2020-06-01

### Added
Expand All @@ -15,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
connection to the ethereum client is reset. This value is specified with an environment
variable `BLOCK_BACKFILL_DEPTH`.
- The chainlink node now sets file permissions on sensitive files on startup (tls, .api, .env, .password and secret)
- AggregatorInterface now has description and version fields.

### Changed

Expand All @@ -27,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`latestRound`, `latestTimestamp`, `getAnswer`, `getTimestamp`) as deprecated
on `FluxAggregator`, `WhitelistedAggregator`, `AggregatorProxy`,
`WhitelistedAggregatorProxy`.
- Updated the solidity compiler version for v0.6 from 0.6.2 to 0.6.6.

### Fixed

Expand Down
10 changes: 7 additions & 3 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ yarndep: ## Ensure all yarn dependencies are installed
gen-builder-cache: gomod # generate a cache for the builder image
yarn install --frozen-lockfile
./tools/bin/restore-solc-cache

.PHONY: install-chainlink
install-chainlink: chainlink ## Install the chainlink binary.
cp $< $(GOBIN)/chainlink
Expand All @@ -71,10 +71,14 @@ operator-ui: ## Build the static frontend UI.
CHAINLINK_VERSION="$(VERSION)@$(COMMIT_SHA)" yarn workspace @chainlink/operator-ui build
CGO_ENABLED=0 go run packr/main.go "${CURDIR}/core/services"

.PHONY: abigen
abigen:
./tools/bin/build_abigen

.PHONY: go-solidity-wrappers
go-solidity-wrappers: ## Recompiles solidity contracts and their go wrappers
go-solidity-wrappers: abigen ## Recompiles solidity contracts and their go wrappers
yarn workspace @chainlink/contracts compile
go generate ./...
go generate ./core/internal/gethwrappers
go run ./packr/main.go ./core/eth/

.PHONY: testdb
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.8.5
0.8.6
3 changes: 2 additions & 1 deletion core/adapters/eth_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ func createTxRunResult(
gasLimit,
)
if err != nil {
logger.Error(errors.Wrap(err, "createTxRunResult failed"))
return models.NewRunOutputPendingOutgoingConfirmationsWithData(input.Data())
}

Expand Down Expand Up @@ -133,7 +134,7 @@ func createTxRunResult(
func ensureTxRunResult(input models.RunInput, str *strpkg.Store) models.RunOutput {
val, err := input.ResultString()
if err != nil {
return models.NewRunOutputError(err)
return models.NewRunOutputError(errors.Wrapf(err, "while processing ethtx input %#+v", input))
}

hash := common.HexToHash(val)
Expand Down
32 changes: 25 additions & 7 deletions core/assets/currencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,42 @@ package assets

import (
"database/sql/driver"
"errors"
"fmt"
"math/big"

"github.com/smartcontractkit/chainlink/core/utils"

"github.com/ethereum/go-ethereum/common"
"github.com/willf/pad"
"github.com/pkg/errors"
)

var ErrNoQuotesForCurrency = errors.New("cannot unmarshal json.Number into currency")

// Memo for {1, 10, 100, 1000, ...}. See getDenominator
var denominators = []*big.Int{big.NewInt(1)}

// getDenominator returns 10**precision.
func getDenominator(precision int) *big.Int {
d := denominators[len(denominators)-1]
base := big.NewInt(10)
// Extend denominators until it contains 10**precision, if necessary
remainingPowers := precision - len(denominators) + 1
for i := 0; i < remainingPowers; i++ {
d = big.NewInt(1).Mul(d, base)
denominators = append(denominators, d)
}
if len(denominators) < precision+1 {
panic(errors.Errorf(
"failed to extend denominators far enough to capture precision: "+
"%s has length %d, but we need length %d", denominators,
len(denominators), precision))
}
// Return a copy of the answer, so the memo can't be messed up
return big.NewInt(0).Set(denominators[precision])
}

func format(i *big.Int, precision int) string {
v := "1" + pad.Right("", precision, "0")
d := &big.Int{}
d.SetString(v, 10)
r := &big.Rat{}
r.SetFrac(i, d)
r := big.NewRat(1, 1).SetFrac(i, getDenominator(precision))
return fmt.Sprintf("%v", r.FloatString(precision))
}

Expand Down
2 changes: 1 addition & 1 deletion core/cmd/local_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func checkFilePermissions(rootDir string) error {
}

// Ensure `$CLROOT/{secret,cookie}` files' permissions are <= `ownerPermsMask``
protectedFiles := []string{"secret", "cookie",".password",".env",".api"}
protectedFiles := []string{"secret", "cookie", ".password", ".env", ".api"}
for _, fileName := range protectedFiles {
path := filepath.Join(rootDir, fileName)
fileInfo, err := os.Stat(path)
Expand Down
31 changes: 21 additions & 10 deletions core/eth/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package eth

import (
"context"
"fmt"
"math/big"

"github.com/smartcontractkit/chainlink/core/assets"
"github.com/smartcontractkit/chainlink/core/logger"
"github.com/smartcontractkit/chainlink/core/utils"

ethereum "github.com/ethereum/go-ethereum"
Expand Down Expand Up @@ -69,7 +71,7 @@ type CallerSubscriber interface {
// GetNonce returns the nonce (transaction count) for a given address.
func (client *CallerSubscriberClient) GetNonce(address common.Address) (uint64, error) {
result := ""
err := client.Call(&result, "eth_getTransactionCount", address.Hex(), "pending")
err := client.logCall(&result, "eth_getTransactionCount", address.Hex(), "pending")
if err != nil {
return 0, err
}
Expand All @@ -80,7 +82,7 @@ func (client *CallerSubscriberClient) GetNonce(address common.Address) (uint64,
func (client *CallerSubscriberClient) GetEthBalance(address common.Address) (*assets.Eth, error) {
result := ""
amount := new(assets.Eth)
err := client.Call(&result, "eth_getBalance", address.Hex(), "latest")
err := client.logCall(&result, "eth_getBalance", address.Hex(), "latest")
if err != nil {
return amount, err
}
Expand All @@ -106,7 +108,7 @@ func (client *CallerSubscriberClient) GetERC20Balance(address common.Address, co
To: contractAddress,
Data: data,
}
err := client.Call(&result, "eth_call", args, "latest")
err := client.logCall(&result, "eth_call", args, "latest")
if err != nil {
return numLinkBigInt, err
}
Expand All @@ -117,50 +119,50 @@ func (client *CallerSubscriberClient) GetERC20Balance(address common.Address, co
// SendRawTx sends a signed transaction to the transaction pool.
func (client *CallerSubscriberClient) SendRawTx(bytes []byte) (common.Hash, error) {
result := common.Hash{}
err := client.Call(&result, "eth_sendRawTransaction", hexutil.Encode(bytes))
err := client.logCall(&result, "eth_sendRawTransaction", hexutil.Encode(bytes))
return result, err
}

// GetTxReceipt returns the transaction receipt for the given transaction hash.
func (client *CallerSubscriberClient) GetTxReceipt(hash common.Hash) (*TxReceipt, error) {
receipt := TxReceipt{}
err := client.Call(&receipt, "eth_getTransactionReceipt", hash.String())
err := client.logCall(&receipt, "eth_getTransactionReceipt", hash.String())
return &receipt, err
}

func (client *CallerSubscriberClient) GetBlockHeight() (uint64, error) {
var height hexutil.Uint64
err := client.Call(&height, "eth_blockNumber")
err := client.logCall(&height, "eth_blockNumber")
return uint64(height), err
}

// GetLatestBlock returns the last committed block of the best blockchain the
// blockchain node is aware of.
func (client *CallerSubscriberClient) GetLatestBlock() (Block, error) {
var block Block
err := client.Call(&block, "eth_getBlockByNumber", "latest", true)
err := client.logCall(&block, "eth_getBlockByNumber", "latest", true)
return block, err
}

// GetBlockByNumber returns the block for the passed hex, or "latest", "earliest", "pending".
// Includes all transactions
func (client *CallerSubscriberClient) GetBlockByNumber(hex string) (Block, error) {
var block Block
err := client.Call(&block, "eth_getBlockByNumber", hex, true)
err := client.logCall(&block, "eth_getBlockByNumber", hex, true)
return block, err
}

// GetLogs returns all logs that respect the passed filter query.
func (client *CallerSubscriberClient) GetLogs(q ethereum.FilterQuery) ([]Log, error) {
var results []Log
err := client.Call(&results, "eth_getLogs", utils.ToFilterArg(q))
err := client.logCall(&results, "eth_getLogs", utils.ToFilterArg(q))
return results, err
}

// GetChainID returns the ethereum ChainID.
func (client *CallerSubscriberClient) GetChainID() (*big.Int, error) {
value := new(utils.Big)
err := client.Call(value, "eth_chainId")
err := client.logCall(value, "eth_chainId")
return value.ToInt(), err
}

Expand All @@ -186,3 +188,12 @@ func (client *CallerSubscriberClient) SubscribeToNewHeads(
sub, err := client.Subscribe(ctx, channel, "newHeads")
return sub, err
}

// logCall logs an RPC call's method and arguments, and then calls the method
func (client *CallerSubscriberClient) logCall(result interface{}, method string, args ...interface{}) error {
logger.Debugw(
fmt.Sprintf(`Calling eth client RPC method "%s"`, method),
"args", args,
)
return client.Call(result, method, args...)
}
1 change: 1 addition & 0 deletions core/internal/cltest/factories.go
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,7 @@ func NewPollingDeviationChecker(t *testing.T, s *strpkg.Store) *fluxmonitor.Poll
runManager := new(mocks.RunManager)
fetcher := new(mocks.Fetcher)
initr := models.Initiator{
JobSpecID: models.NewID(),
InitiatorParams: models.InitiatorParams{
PollTimer: models.PollTimerConfig{
Period: models.MustMakeDuration(time.Second),
Expand Down
86 changes: 86 additions & 0 deletions core/internal/gethwrappers/extract_contract_details.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package gethwrappers

import (
"crypto/sha256"
"encoding/json"
"fmt"
"io/ioutil"
"regexp"

"github.com/pkg/errors"
"github.com/tidwall/gjson"

"github.com/smartcontractkit/chainlink/core/utils"
)

// ContractDetails contains the contract data needed to make a geth contract
// wrapper for a solidity contract.
type ContractDetails struct {
Binary string // Hex representation of the contract's raw bytes
ABI string
Sources map[string]string // contractName -> source code
}

// c.VersionHash() is the hash used to detect changes in the underlying contract
func (c *ContractDetails) VersionHash() (hash string) {
hashMsg := c.ABI + c.Binary + "\n"
return fmt.Sprintf("%x", sha256.Sum256([]byte(hashMsg)))
}

// ExtractContractDetails returns the data in the belt artifact needed to make a
// geth contract wrapper for the corresponding EVM contract
func ExtractContractDetails(beltArtifactPath string) (*ContractDetails, error) {
beltArtifact, err := ioutil.ReadFile(beltArtifactPath)
if err != nil {
return nil, errors.Wrapf(err, "could not read belt artifact; you may need "+
" to run`yarn && yarn workspace @chainlink/contracts belt compile solc`")
}
rawABI := gjson.Get(string(beltArtifact), "compilerOutput.abi")
contractABI, err := utils.NormalizedJSON([]byte(rawABI.String()))
if err != nil {
return nil, errors.Wrapf(err, "could not parse belt ABI JSON as JSON")
}

// We want the bytecode here, not the deployedByteCode. The latter does not
// include the initialization code.
rawBinary := gjson.Get(string(beltArtifact),
"compilerOutput.evm.bytecode.object").String()
if rawBinary == "" {
return nil, errors.Errorf(
"could not parse belt contract binary JSON as JSON")
}

// Since the binary metadata suffix varies so much, it can't be included in a
// reliable check that the golang wrapper is up-to-date, so remove it from the
// message hash.
truncLen := len(rawBinary) - 106
truncatedBinary := rawBinary[:truncLen]
suffix := rawBinary[truncLen:]
// Verify that the suffix follows the pattern outlined in the above link, to
// ensure that we're actually truncating what we think we are.
if !binarySuffixRegexp(suffix) {
return nil, errors.Errorf(
"binary suffix has unexpected format; giving up: "+suffix, nil)
}
var sources struct {
Sources map[string]string `json:"sourceCodes"`
}
if err := json.Unmarshal(beltArtifact, &sources); err != nil {
return nil, errors.Wrapf(err, "could not read source code from compiler artifact")
}
return &ContractDetails{
Binary: truncatedBinary,
ABI: contractABI,
Sources: sources.Sources,
}, nil
}

// binarySuffixRegexp checks that the hex representation of the trailing bytes
// of a contract wrapper follow the expected metadata format.
//
// Modern solc objects have metadata suffixes which vary depending on
// incidental compilation context like absolute paths to source files. See
// https://solidity.readthedocs.io/en/v0.6.2/metadata.html#encoding-of-the-metadata-hash-in-the-bytecode
var binarySuffixRegexp = regexp.MustCompile(
"^a264697066735822[[:xdigit:]]{68}64736f6c6343[[:xdigit:]]{6}0033$",
).MatchString
Loading

0 comments on commit 9e8254c

Please sign in to comment.