Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ocr3config/return active candidate #285

Merged
merged 11 commits into from
Nov 4, 2024
12 changes: 10 additions & 2 deletions commit/plugin_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"testing"
"time"

ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"

"github.com/smartcontractkit/chainlink-ccip/internal/libs/mathslib"
"github.com/smartcontractkit/chainlink-ccip/internal/libs/testhelpers/rand"

Expand Down Expand Up @@ -721,7 +723,11 @@ func setupNode(params SetupNodeParams, nodeID commontypes.OracleID) nodeSetup {
homeChainReader.EXPECT().GetFChain().Return(fChain, nil)
homeChainReader.EXPECT().
GetOCRConfigs(mock.Anything, params.donID, consts.PluginTypeCommit).
Return([]reader.OCR3ConfigWithMeta{{}}, nil).Maybe()
Return(reader.ActiveAndCandidate{
ActiveConfig: reader.OCR3ConfigWithMeta{
ConfigDigest: params.reportingCfg.ConfigDigest,
},
}, nil).Maybe()

for peerID, supportedChains := range supportedChainsForPeer {
homeChainReader.EXPECT().GetSupportedChainsForPeer(peerID).Return(supportedChains, nil).Maybe()
Expand Down Expand Up @@ -825,6 +831,8 @@ func defaultNodeParams(t *testing.T) SetupNodeParams {
lggr := logger.Test(t)

donID := uint32(1)
rb := rand.RandomBytes32()
digest := ocrtypes.ConfigDigest(rb[:])

require.Equal(t, len(oracleIDs), len(peerIDs))

Expand Down Expand Up @@ -864,7 +872,7 @@ func defaultNodeParams(t *testing.T) SetupNodeParams {
PriceFeedChainSelector: sourceChain1,
}

reportingCfg := ocr3types.ReportingPluginConfig{F: 1}
reportingCfg := ocr3types.ReportingPluginConfig{F: 1, ConfigDigest: digest}

params := SetupNodeParams{
ctx: ctx,
Expand Down
4 changes: 2 additions & 2 deletions commit/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func (p *Plugin) ShouldTransmitAcceptedReport(
}

// we only transmit reports if we are the "active" instance.
// we can check this by reading the OCR conigs home chain.
// we can check this by reading the OCR configs from the home chain.
isCandidate, err := p.isCandidateInstance(ctx)
if err != nil {
return false, fmt.Errorf("isCandidateInstance: %w", err)
Expand Down Expand Up @@ -171,5 +171,5 @@ func (p *Plugin) isCandidateInstance(ctx context.Context) (bool, error) {
return false, fmt.Errorf("failed to get ocr configs from home chain: %w", err)
}

return len(ocrConfigs) == 2 && ocrConfigs[1].ConfigDigest == p.reportingCfg.ConfigDigest, nil
return ocrConfigs.CandidateConfig.ConfigDigest == p.reportingCfg.ConfigDigest, nil
0xAustinWang marked this conversation as resolved.
Show resolved Hide resolved
}
137 changes: 137 additions & 0 deletions commit/report_test.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
package commit

import (
"fmt"
"testing"

"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"

"github.com/smartcontractkit/chainlink-ccip/internal/libs/testhelpers/rand"
reader_mock "github.com/smartcontractkit/chainlink-ccip/mocks/internal_/reader"
"github.com/smartcontractkit/chainlink-ccip/pkg/consts"

"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"

"github.com/smartcontractkit/libocr/offchainreporting2plus/types"

"github.com/smartcontractkit/chainlink-ccip/commit/chainfee"
"github.com/smartcontractkit/chainlink-ccip/commit/merkleroot"
rmntypes "github.com/smartcontractkit/chainlink-ccip/commit/merkleroot/rmn/types"
"github.com/smartcontractkit/chainlink-ccip/commit/tokenprice"
"github.com/smartcontractkit/chainlink-ccip/internal/mocks"
"github.com/smartcontractkit/chainlink-ccip/internal/reader"
"github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3"
)

Expand Down Expand Up @@ -153,3 +165,128 @@ func TestPluginReports_InvalidOutcome(t *testing.T) {
_, err := p.Reports(tests.Context(t), 0, []byte("invalid json"))
require.Error(t, err)
}

func Test_IsCandidateCheck(t *testing.T) {
rb := rand.RandomBytes32()
digest := types.ConfigDigest(rb[:])
donID := uint32(3)
allTests := []struct {
name string
makePlugin func(t *testing.T, hc *reader_mock.MockHomeChain) *Plugin
makeHomeChain func(t *testing.T) *reader_mock.MockHomeChain
wantOutput bool
wantError bool
}{
{
name: "Should return true if digest matches",
makePlugin: func(t *testing.T, hc *reader_mock.MockHomeChain) *Plugin {
p := &Plugin{
homeChain: hc,
reportingCfg: ocr3types.ReportingPluginConfig{
ConfigDigest: digest,
},
}
return p
},
makeHomeChain: func(t *testing.T) *reader_mock.MockHomeChain {
h := reader_mock.NewMockHomeChain(t)
h.On("GetOCRConfigs", mock.Anything, mock.Anything, consts.PluginTypeCommit).
Return(reader.ActiveAndCandidate{
ActiveConfig: reader.OCR3ConfigWithMeta{},
CandidateConfig: reader.OCR3ConfigWithMeta{
ConfigDigest: digest,
},
}, nil)
return h
},
wantOutput: true,
wantError: false,
},
{
name: "Should return false if digest doesn't match",
makePlugin: func(t *testing.T, hc *reader_mock.MockHomeChain) *Plugin {
p := &Plugin{
homeChain: hc,
reportingCfg: ocr3types.ReportingPluginConfig{
ConfigDigest: types.ConfigDigest(rand.RandomBytes32()),
},
}
return p
},
makeHomeChain: func(t *testing.T) *reader_mock.MockHomeChain {
h := reader_mock.NewMockHomeChain(t)
h.On("GetOCRConfigs", mock.Anything, mock.Anything, consts.PluginTypeCommit).
Return(reader.ActiveAndCandidate{
ActiveConfig: reader.OCR3ConfigWithMeta{},
CandidateConfig: reader.OCR3ConfigWithMeta{
ConfigDigest: digest,
},
}, nil)
return h
},
wantOutput: false,
wantError: false,
},
{
name: "Should work as expected without candidate instance",
makePlugin: func(t *testing.T, hc *reader_mock.MockHomeChain) *Plugin {
p := &Plugin{
homeChain: hc,
reportingCfg: ocr3types.ReportingPluginConfig{
ConfigDigest: types.ConfigDigest(rand.RandomBytes32()),
},
}
return p
},
makeHomeChain: func(t *testing.T) *reader_mock.MockHomeChain {
h := reader_mock.NewMockHomeChain(t)
h.On("GetOCRConfigs", mock.Anything, mock.Anything, consts.PluginTypeCommit).
Return(reader.ActiveAndCandidate{
ActiveConfig: reader.OCR3ConfigWithMeta{},
CandidateConfig: reader.OCR3ConfigWithMeta{},
}, nil)
return h
},
wantOutput: false,
wantError: false,
},
{
name: "Should throw error if donID doesn't exist",
makePlugin: func(t *testing.T, hc *reader_mock.MockHomeChain) *Plugin {
p := &Plugin{
homeChain: hc,
donID: donID,
reportingCfg: ocr3types.ReportingPluginConfig{
ConfigDigest: types.ConfigDigest(rand.RandomBytes32()),
},
}
return p
},
makeHomeChain: func(t *testing.T) *reader_mock.MockHomeChain {
h := reader_mock.NewMockHomeChain(t)
h.On("GetOCRConfigs", mock.Anything, donID, consts.PluginTypeCommit).
Return(reader.ActiveAndCandidate{
ActiveConfig: reader.OCR3ConfigWithMeta{},
CandidateConfig: reader.OCR3ConfigWithMeta{},
}, fmt.Errorf("DonID does not exist"))
return h
},
wantOutput: false,
wantError: true,
},
}
for _, tt := range allTests {
t.Run(tt.name, func(t *testing.T) {
ctx := tests.Context(t)
hc := tt.makeHomeChain(t)
p := tt.makePlugin(t, hc)
actualOutput, actualError := p.isCandidateInstance(ctx)
assert.Equal(t, tt.wantOutput, actualOutput)
if tt.wantError {
require.Error(t, actualError)
} else {
require.NoError(t, actualError)
}
})
}
}
16 changes: 8 additions & 8 deletions execute/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,15 +300,15 @@ func (p *Plugin) ShouldTransmitAcceptedReport(
return false, nil
}

// we only transmit reports if we are the "blue" instance.
// we can check this by reading the OCR conigs home chain.
isGreen, err := p.isGreenInstance(ctx)
// we only transmit reports if we are the "active" instance.
// we can check this by reading the OCR configs home chain.
isCandidate, err := p.isCandidateInstance(ctx)
if err != nil {
return false, fmt.Errorf("ShouldTransmitAcceptedReport.isGreenInstance: %w", err)
return false, fmt.Errorf("ShouldTransmitAcceptedReport.isCandidateInstance: %w", err)
}

if isGreen {
p.lggr.Debugw("not the blue instance, skipping report transmission",
if isCandidate {
p.lggr.Debugw("not the active instance, skipping report transmission",
"myDigest", p.reportingCfg.ConfigDigest.Hex())
return false, nil
}
Expand All @@ -324,13 +324,13 @@ func (p *Plugin) ShouldTransmitAcceptedReport(
return true, nil
}

func (p *Plugin) isGreenInstance(ctx context.Context) (bool, error) {
func (p *Plugin) isCandidateInstance(ctx context.Context) (bool, error) {
ocrConfigs, err := p.homeChain.GetOCRConfigs(ctx, p.donID, consts.PluginTypeExecute)
if err != nil {
return false, fmt.Errorf("failed to get ocr configs from home chain: %w", err)
}

return len(ocrConfigs) == 2 && ocrConfigs[1].ConfigDigest == p.reportingCfg.ConfigDigest, nil
return ocrConfigs.CandidateConfig.ConfigDigest == p.reportingCfg.ConfigDigest, nil
}

func (p *Plugin) Close() error {
Expand Down
33 changes: 21 additions & 12 deletions execute/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"testing"
"time"

"github.com/smartcontractkit/chainlink-ccip/internal/libs/testhelpers/rand"

mapset "github.com/deckarep/golang-set/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
Expand All @@ -24,11 +26,10 @@ import (
"github.com/smartcontractkit/chainlink-ccip/execute/exectypes"
"github.com/smartcontractkit/chainlink-ccip/internal/libs/slicelib"
dt "github.com/smartcontractkit/chainlink-ccip/internal/plugincommon/discovery/discoverytypes"
"github.com/smartcontractkit/chainlink-ccip/internal/reader"
reader_mock "github.com/smartcontractkit/chainlink-ccip/mocks/internal_/reader"
readerpkg_mock "github.com/smartcontractkit/chainlink-ccip/mocks/pkg/reader"
codec_mocks "github.com/smartcontractkit/chainlink-ccip/mocks/pkg/types/ccipocr3"
"github.com/smartcontractkit/chainlink-ccip/pkg/consts"
"github.com/smartcontractkit/chainlink-ccip/pkg/reader"
cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3"
plugintypes2 "github.com/smartcontractkit/chainlink-ccip/plugintypes"
)
Expand Down Expand Up @@ -531,12 +532,16 @@ func TestPlugin_ShouldTransmitAcceptReport_Ineligible(t *testing.T) {

func TestPlugin_ShouldTransmitAcceptReport_DecodeFailure(t *testing.T) {
const donID = uint32(1)
rb := rand.RandomBytes32()
digest := types.ConfigDigest(rb[:])
homeChain := reader_mock.NewMockHomeChain(t)
homeChain.On("GetSupportedChainsForPeer", mock.Anything).Return(mapset.NewSet(cciptypes.ChainSelector(1)), nil)
homeChain.
EXPECT().
GetOCRConfigs(mock.Anything, donID, consts.PluginTypeExecute).
Return([]reader.OCR3ConfigWithMeta{{}}, nil)
homeChain.On("GetOCRConfigs", mock.Anything, mock.Anything, mock.Anything).
Return(reader.ActiveAndCandidate{
ActiveConfig: reader.OCR3ConfigWithMeta{
ConfigDigest: digest,
},
}, nil)
codec := codec_mocks.NewMockExecutePluginCodec(t)
codec.On("Decode", mock.Anything, mock.Anything).
Return(cciptypes.ExecutePluginReport{}, fmt.Errorf("test error"))
Expand All @@ -545,7 +550,7 @@ func TestPlugin_ShouldTransmitAcceptReport_DecodeFailure(t *testing.T) {
donID: donID,
lggr: logger.Test(t),
destChain: 1,
reportingCfg: ocr3types.ReportingPluginConfig{OracleID: 2},
reportingCfg: ocr3types.ReportingPluginConfig{OracleID: 2, ConfigDigest: digest},
reportCodec: codec,
homeChain: homeChain,
oracleIDToP2pID: map[commontypes.OracleID]libocrtypes.PeerID{
Expand All @@ -560,13 +565,17 @@ func TestPlugin_ShouldTransmitAcceptReport_DecodeFailure(t *testing.T) {

func TestPlugin_ShouldTransmitAcceptReport_Success(t *testing.T) {
const donID = uint32(1)
rb := rand.RandomBytes32()
digest := types.ConfigDigest(rb[:])
lggr, logs := logger.TestObserved(t, zapcore.DebugLevel)
homeChain := reader_mock.NewMockHomeChain(t)
homeChain.On("GetSupportedChainsForPeer", mock.Anything).Return(mapset.NewSet(cciptypes.ChainSelector(1)), nil)
homeChain.
EXPECT().
GetOCRConfigs(mock.Anything, donID, consts.PluginTypeExecute).
Return([]reader.OCR3ConfigWithMeta{{}}, nil)
homeChain.On("GetOCRConfigs", mock.Anything, mock.Anything, mock.Anything).
Return(reader.ActiveAndCandidate{
ActiveConfig: reader.OCR3ConfigWithMeta{
ConfigDigest: digest,
},
}, nil)
codec := codec_mocks.NewMockExecutePluginCodec(t)
codec.On("Decode", mock.Anything, mock.Anything).
Return(cciptypes.ExecutePluginReport{}, nil)
Expand All @@ -575,7 +584,7 @@ func TestPlugin_ShouldTransmitAcceptReport_Success(t *testing.T) {
donID: donID,
lggr: lggr,
destChain: 1,
reportingCfg: ocr3types.ReportingPluginConfig{OracleID: 2},
reportingCfg: ocr3types.ReportingPluginConfig{OracleID: 2, ConfigDigest: digest},
reportCodec: codec,
homeChain: homeChain,
oracleIDToP2pID: map[commontypes.OracleID]libocrtypes.PeerID{
Expand Down
10 changes: 7 additions & 3 deletions execute/test_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package execute

import (
"context"
crand "crypto/rand"
"encoding/binary"
"net/http"
"net/http/httptest"
Expand All @@ -14,6 +15,7 @@ import (

"github.com/smartcontractkit/libocr/commontypes"
"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
libocrtypes "github.com/smartcontractkit/libocr/ragep2p/types"

commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config"
Expand Down Expand Up @@ -288,10 +290,12 @@ func (it *IntTest) newNode(
N int,
) nodeSetup {
reportCodec := mocks.NewExecutePluginJSONReportCodec()

b := make([]byte, 32)
_, _ = crand.Read(b)
rCfg := ocr3types.ReportingPluginConfig{
N: N,
OracleID: commontypes.OracleID(id),
N: N,
OracleID: commontypes.OracleID(id),
ConfigDigest: ocrtypes.ConfigDigest(b),
}

node1 := NewPlugin(
Expand Down
Loading
Loading