Decoder registry: don't panic if multiple calls with same parameters to `RegisterInstructionDecoder` func

This commit is contained in:
gagliardetto 2022-02-05 16:07:36 +01:00
parent 7714a012fa
commit 4d4bc9a2f2
2 changed files with 40 additions and 2 deletions

View File

@ -20,6 +20,7 @@ package solana
import (
"errors"
"fmt"
"reflect"
"sync"
)
@ -77,10 +78,20 @@ func (reg *decoderRegistry) RegisterIfNew(programID PublicKey, decoder Instructi
}
func RegisterInstructionDecoder(programID PublicKey, decoder InstructionDecoder) {
isNew := instructionDecoderRegistry.RegisterIfNew(programID, decoder)
if !isNew {
prev, has := instructionDecoderRegistry.Get(programID)
if has {
// If it's the same function, then OK (tollerate multiple calls with same params).
if isSameFunction(prev, decoder) {
return
}
// If it's another decoder for the same pubkey, then panic.
panic(fmt.Sprintf("unable to re-register instruction decoder for program %s", programID))
}
instructionDecoderRegistry.RegisterIfNew(programID, decoder)
}
func isSameFunction(f1 interface{}, f2 interface{}) bool {
return reflect.ValueOf(f1).Pointer() == reflect.ValueOf(f2).Pointer()
}
func DecodeInstruction(programID PublicKey, accounts []*AccountMeta, data []byte) (interface{}, error) {

27
registry_test.go Normal file
View File

@ -0,0 +1,27 @@
package solana
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestRegisterInstructionDecoder(t *testing.T) {
decoder := func(instructionAccounts []*AccountMeta, data []byte) (interface{}, error) {
return nil, nil
}
decoderAnother := func(instructionAccounts []*AccountMeta, data []byte) (interface{}, error) {
return nil, nil
}
assert.NotPanics(t, func() {
RegisterInstructionDecoder(BPFLoaderProgramID, decoder)
})
assert.NotPanics(t, func() {
RegisterInstructionDecoder(BPFLoaderProgramID, decoder)
})
assert.Panics(t, func() {
RegisterInstructionDecoder(BPFLoaderProgramID, decoderAnother)
})
}