node/accountant: defense-in-depth ensure accountant does not create messages outside its domain
This commit is contained in:
parent
718cd3b1b3
commit
fc1ca4ffb9
|
@ -192,12 +192,10 @@ func (acct *Accountant) FeatureString() string {
|
||||||
return "acct:enforced"
|
return "acct:enforced"
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubmitObservation will submit token bridge transfers to the accountant smart contract. This is called from the processor
|
// IsMessageCoveredByAccountant returns `true` if a message should be processed by the Global Accountant, `false` if not.
|
||||||
// loop when a local observation is received from a watcher. It returns true if the observation can be published immediately,
|
func (acct *Accountant) IsMessageCoveredByAccountant(msg *common.MessagePublication) bool {
|
||||||
// false if not (because it has been submitted to accountant).
|
|
||||||
func (acct *Accountant) SubmitObservation(msg *common.MessagePublication) (bool, error) {
|
|
||||||
msgId := msg.MessageIDString()
|
msgId := msg.MessageIDString()
|
||||||
acct.logger.Debug("acct: in SubmitObservation", zap.String("msgID", msgId))
|
|
||||||
// We only care about token bridges.
|
// We only care about token bridges.
|
||||||
tbk := tokenBridgeKey{emitterChainId: msg.EmitterChain, emitterAddr: msg.EmitterAddress}
|
tbk := tokenBridgeKey{emitterChainId: msg.EmitterChain, emitterAddr: msg.EmitterAddress}
|
||||||
if _, exists := acct.tokenBridges[tbk]; !exists {
|
if _, exists := acct.tokenBridges[tbk]; !exists {
|
||||||
|
@ -205,12 +203,26 @@ func (acct *Accountant) SubmitObservation(msg *common.MessagePublication) (bool,
|
||||||
acct.logger.Debug("acct: ignoring vaa because it is not a token bridge", zap.String("msgID", msgId))
|
acct.logger.Debug("acct: ignoring vaa because it is not a token bridge", zap.String("msgID", msgId))
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only care about transfers.
|
// We only care about transfers.
|
||||||
if !vaa.IsTransfer(msg.Payload) {
|
if !vaa.IsTransfer(msg.Payload) {
|
||||||
acct.logger.Info("acct: ignoring vaa because it is not a transfer", zap.String("msgID", msgId))
|
acct.logger.Info("acct: ignoring vaa because it is not a transfer", zap.String("msgID", msgId))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubmitObservation will submit token bridge transfers to the accountant smart contract. This is called from the processor
|
||||||
|
// loop when a local observation is received from a watcher. It returns true if the observation can be published immediately,
|
||||||
|
// false if not (because it has been submitted to accountant).
|
||||||
|
func (acct *Accountant) SubmitObservation(msg *common.MessagePublication) (bool, error) {
|
||||||
|
msgId := msg.MessageIDString()
|
||||||
|
acct.logger.Debug("acct: in SubmitObservation", zap.String("msgID", msgId))
|
||||||
|
|
||||||
|
if !acct.IsMessageCoveredByAccountant(msg) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -230,6 +230,10 @@ func (p *Processor) Run(ctx context.Context) error {
|
||||||
if p.acct == nil {
|
if p.acct == nil {
|
||||||
return fmt.Errorf("acct: received an accountant event when accountant is not configured")
|
return fmt.Errorf("acct: received an accountant event when accountant is not configured")
|
||||||
}
|
}
|
||||||
|
// SECURITY defense-in-depth: Make sure the accountant did not generate an unexpected message.
|
||||||
|
if !p.acct.IsMessageCoveredByAccountant(k) {
|
||||||
|
return fmt.Errorf("acct: accountant published a message that is not covered by it: `%s`", k.MessageIDString())
|
||||||
|
}
|
||||||
p.handleMessage(ctx, k)
|
p.handleMessage(ctx, k)
|
||||||
case v := <-p.injectC:
|
case v := <-p.injectC:
|
||||||
p.handleInjection(ctx, v)
|
p.handleInjection(ctx, v)
|
||||||
|
|
Loading…
Reference in New Issue