Skip to content

Commit fe8d03e

Browse files
authored
feat: support pigeon operator keys (#330)
# Related Github tickets - VolumeFi/paloma#857 - VolumeFi/paloma#934 - palomachain/paloma#1025 # Background In order to support multiple signing keys for Pigeons, we recently released a change for Paloma that introduced message metadata fields for all Paloma messages, allowing Pigeons to define signers other than the creator address. This change includes: - Removing lens as a dependency, replacing it with a slimmed down in-house solution called `ion` - Support to define multiple signature keys in the pigeon config, see below for additional details - Automatic key rotation when sending messages to Paloma - Automatic metadata injection into messages - Introducing `validator-key` as a configuration field for the paloma chain inside Pigeon. This used to be the `signing-key` field, which remains to be supported for now The new signing keys are completely optional. In case there's no change to the configuration, Pigeon will read the old existing `signature-key` field and use it for both the message creator and signer when injecting metadata. See below on how to enable support for multiple signing keys. Going forward, we'll be referring to the old `signing-key` as `validator-key`. #### Support for multiple signing keys By default, Pigeon will use your validator key to sign any transactions sent to Paloma. In high throughput environments, this may lead to `account sequence mismatch` errors. It's possible to define more than one signing key to be used in rotation to combat this issue. In order to do so, you will need to create a number of new keys and register them with Pigeon like this: ```bash # First, create a number of new keys. You may create an arbitrary amount of keys. palomad keys add pigeon-operator-alpha palomad keys add pigeon-operator-bravo palomad keys add pigeon-operator-charlie # Second, your new addresses will need to receive an active feegrant from your validator address. # This step is very important. It's not enough to simply fund those addresses manually. # The active feegrant is considered a "permission" to send transactions from your validator address". palomad tx feegrant grant $VALIDATOR_ADDRESS pigeon-operator-alpha --fees 500ugrain -y palomad tx feegrant grant $VALIDATOR_ADDRESS pigeon-operator-bravo --fees 500ugrain -y palomad tx feegrant grant $VALIDATOR_ADDRESS pigeon-operator-charlie --fees 500ugrain -y ``` After creating your signing keys, all you need to do is register them with Pigeon by adding the following to your pigeon config. Make sure to restart the service after making these changes. ```yaml paloma: signing-keys: - pigeon-operator-alpha - pigeon-operator-bravo - pigeon-operator-charlie ``` # Testing completed - [x] test coverage exists or has been added/updated - [x] tested in a private testnet # Breaking changes - [x] I have checked my code for breaking changes --- * feat: support multiple signing keys with rotation * fix: use master address when sending messages * fix: dead lock on mutex acquisition * feat: add fee grant * chore: add logging * feat: inject message metadata * fix: retrieve signer address for metadata * fix: remove superfluous logging * feat: remove locking from paloma calls * fix: use paloma wrapper constructor * chore: remove all lens dependencies * fix: CI pipeline * chore: move signature keys configuration to paloma only * chore: update go.mod paloma reference * doc: update README
1 parent 9b1dd77 commit fe8d03e

36 files changed

+2803
-748
lines changed

.github/workflows/ci-test.yml

+17-4
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,38 @@ on:
44
- "*"
55

66
jobs:
7-
run-tests:
7+
run_tests:
8+
name: Running tests
89
runs-on: ubuntu-latest
910
steps:
1011
- name: Checkout
1112
uses: actions/checkout@v4
1213
- name: Set up Go
1314
uses: actions/setup-go@v4
1415
with:
15-
go-version: '1.20'
16+
go-version: '1.21'
17+
cache: false
1618
- name: Run tests
1719
run: go test -v ./...
20+
run_linters:
21+
name: Running linters
22+
runs-on: ubuntu-latest
23+
steps:
24+
- name: Checkout
25+
uses: actions/checkout@v4
26+
- name: Set up Go
27+
uses: actions/setup-go@v4
28+
with:
29+
go-version: '1.21'
30+
cache: false
1831
- name: Go lint
1932
uses: golangci/golangci-lint-action@v3
2033
with:
21-
version: v1.51.2
34+
version: v1.55.2
2235
args: --verbose
2336
# Optional: if set to true then the all caching functionality will be complete disabled,
2437
# takes precedence over all other caching options.
25-
# skip-cache: true
38+
skip-cache: true
2639

2740
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
2841
skip-pkg-cache: true

README.md

+29-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ paloma:
176176
keyring-dir: ~/.paloma
177177
keyring-pass-env-name: PALOMA_KEYRING_PASS
178178
keyring-type: os
179-
signing-key: ${VALIDATOR}
179+
validator-key: ${VALIDATOR}
180180
base-rpc-url: http://localhost:26657
181181
gas-adjustment: 3.0
182182
gas-prices: 0.01ugrain
@@ -256,6 +256,34 @@ evm:
256256
tx-type: 2
257257
```
258258
259+
#### Support for multiple signing keys
260+
261+
By default, Pigeon will use your validator key to sign any transactions sent to Paloma. In high throughput environments, this may lead to `account sequence mismatch` errors.
262+
It's possible to define more than one signing key to be used in rotation to combat this issue. In order to do so, you will need to create a number of new keys and register them with Pigeon like this:
263+
264+
```bash
265+
# First, create a number of new keys. You may create an arbitrary amount of keys.
266+
palomad keys add pigeon-operator-alpha
267+
palomad keys add pigeon-operator-bravo
268+
palomad keys add pigeon-operator-charlie
269+
270+
# Second, your new addresses will need to receive an active feegrant from your validator address.
271+
# This step is very important. It's not enough to simply fund those addresses manually.
272+
# The active feegrant is considered a "permission" to send transactions from your validator address".
273+
palomad tx feegrant grant $VALIDATOR_ADDRESS pigeon-operator-alpha --fees 500ugrain -y
274+
palomad tx feegrant grant $VALIDATOR_ADDRESS pigeon-operator-bravo --fees 500ugrain -y
275+
palomad tx feegrant grant $VALIDATOR_ADDRESS pigeon-operator-charlie --fees 500ugrain -y
276+
```
277+
278+
After creating your signing keys, all you need to do is register them with Pigeon by adding the following to your pigeon config. Make sure to restart the service after making these changes.
279+
280+
```yaml
281+
paloma:
282+
signing-keys:
283+
- pigeon-operator-alpha
284+
- pigeon-operator-bravo
285+
- pigeon-operator-charlie
286+
```
259287

260288
### Start pigeon
261289

app/app.go

+32-20
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@ import (
1414
gravitytypes "github.com/palomachain/paloma/x/gravity/types"
1515
palomatypes "github.com/palomachain/paloma/x/paloma/types"
1616
valsettypes "github.com/palomachain/paloma/x/valset/types"
17-
"github.com/palomachain/pigeon/chain"
1817
"github.com/palomachain/pigeon/chain/evm"
1918
"github.com/palomachain/pigeon/chain/paloma"
2019
"github.com/palomachain/pigeon/config"
2120
"github.com/palomachain/pigeon/health"
2221
"github.com/palomachain/pigeon/relayer"
22+
"github.com/palomachain/pigeon/util/ion"
23+
"github.com/palomachain/pigeon/util/ion/byop"
24+
"github.com/palomachain/pigeon/util/rotator"
2325
"github.com/palomachain/pigeon/util/time"
2426
log "github.com/sirupsen/logrus"
25-
"github.com/strangelove-ventures/lens/byop"
26-
lens "github.com/strangelove-ventures/lens/client"
2727
)
2828

2929
const (
@@ -64,7 +64,7 @@ func Relayer() *relayer.Relayer {
6464
if _relayer == nil {
6565
_relayer = relayer.New(
6666
Config(),
67-
*PalomaClient(),
67+
PalomaClient(),
6868
EvmFactory(),
6969
Time(),
7070
relayer.Config{
@@ -118,6 +118,16 @@ func Config() *config.Config {
118118
"err": err,
119119
}).Fatal("couldn't read config file")
120120
}
121+
122+
if len(cnf.Paloma.ValidatorKey) < 1 {
123+
// TODO: Remove legacy SigningKey field after successful migration
124+
cnf.Paloma.ValidatorKey = cnf.Paloma.SigningKey
125+
}
126+
if len(cnf.Paloma.SigningKeys) < 1 {
127+
log.Info("No signing key collection provided, falling back to using validator key for signing")
128+
cnf.Paloma.SigningKeys = []string{cnf.Paloma.ValidatorKey}
129+
}
130+
121131
_config = cnf
122132
}
123133

@@ -127,26 +137,29 @@ func Config() *config.Config {
127137
func PalomaClient() *paloma.Client {
128138
if _palomaClient == nil {
129139
palomaConfig := Config().Paloma
130-
131-
lensConfig := palomaLensClientConfig(palomaConfig)
140+
clientCfg := palomaClientConfig(palomaConfig)
132141

133142
// HACK: \n is added at the end of a password because github.com/cosmos/[email protected]/client/input/input.go at line 93 would return an EOF error which then would fail
134143
// Should be fixed with https://github.com/cosmos/cosmos-sdk/pull/11796
135144
passInput := strings.NewReader(config.KeyringPassword(palomaConfig.KeyringPassEnvName) + "\n")
136-
137-
lensClient := whoops.Must(chain.NewChainClient(
138-
lensConfig,
145+
ionClient := whoops.Must(ion.NewClient(
146+
clientCfg,
139147
passInput,
140148
os.Stdout,
141149
))
142150

143-
_palomaClient = &paloma.Client{
144-
L: lensClient,
145-
GRPCClient: paloma.GRPCClientDowner{W: lensClient},
146-
MessageSender: paloma.MessageSenderDowner{W: lensClient},
147-
PalomaConfig: palomaConfig,
151+
// Always pass configurations as pointers to enable updates during runtime!
152+
// TODO: Move rotator & paloma client wrapper functionalities directly into ion client
153+
fn := func(s string) {
154+
clientCfg.Key = s
148155
}
149-
_palomaClient.Init()
156+
r := rotator.New(fn, palomaConfig.SigningKeys...)
157+
158+
grpcWrapper := &paloma.GRPCClientWrapper{W: ionClient}
159+
senderWrapper := paloma.NewPalomaMessageSender(r, ionClient)
160+
_palomaClient = paloma.NewClient(palomaConfig, grpcWrapper, ionClient, senderWrapper, ionClient)
161+
senderWrapper.WithCreatorProvider(_palomaClient.GetCreator)
162+
senderWrapper.WithSignerProvider(_palomaClient.GetSigner)
150163
}
151164
return _palomaClient
152165
}
@@ -159,8 +172,8 @@ func defaultValue[T comparable](proposedVal T, defaultVal T) T {
159172
return proposedVal
160173
}
161174

162-
func palomaLensClientConfig(palomaConfig config.Paloma) *lens.ChainClientConfig {
163-
modules := lens.ModuleBasics[:]
175+
func palomaClientConfig(palomaConfig config.Paloma) *ion.ChainClientConfig {
176+
modules := ion.ModuleBasics[:]
164177

165178
modules = append(modules, byop.Module{
166179
ModuleName: "paloma",
@@ -172,7 +185,6 @@ func palomaLensClientConfig(palomaConfig config.Paloma) *lens.ChainClientConfig
172185
&consensustypes.MsgAddMessagesSignatures{},
173186
&valsettypes.MsgAddExternalChainInfoForValidator{},
174187
&valsettypes.MsgKeepAlive{},
175-
&consensustypes.MsgDeleteJob{},
176188
&consensustypes.MsgAddEvidence{},
177189
&consensustypes.MsgSetPublicAccessData{},
178190
&consensustypes.MsgSetErrorData{},
@@ -210,8 +222,8 @@ func palomaLensClientConfig(palomaConfig config.Paloma) *lens.ChainClientConfig
210222
},
211223
})
212224

213-
return &lens.ChainClientConfig{
214-
Key: palomaConfig.SigningKey,
225+
return &ion.ChainClientConfig{
226+
Key: palomaConfig.SigningKeys[0],
215227
ChainID: defaultValue(palomaConfig.ChainID, "paloma"),
216228
RPCAddr: defaultValue(palomaConfig.BaseRPCURL, "http://127.0.0.1:26657"),
217229
AccountPrefix: defaultValue(palomaConfig.AccountPrefix, "paloma"),

chain/client.go

-53
This file was deleted.

0 commit comments

Comments
 (0)