Codespaces as Strings (#2821)
This commit is contained in:
@@ -1,35 +0,0 @@
|
||||
package types
|
||||
|
||||
// Codespacer is a simple struct to track reserved codespaces
|
||||
type Codespacer struct {
|
||||
reserved map[CodespaceType]bool
|
||||
}
|
||||
|
||||
// NewCodespacer generates a new Codespacer with the starting codespace
|
||||
func NewCodespacer() *Codespacer {
|
||||
return &Codespacer{
|
||||
reserved: make(map[CodespaceType]bool),
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterNext reserves and returns the next available codespace, starting from a default, and panics if the maximum codespace is reached
|
||||
func (c *Codespacer) RegisterNext(codespace CodespaceType) CodespaceType {
|
||||
for {
|
||||
if !c.reserved[codespace] {
|
||||
c.reserved[codespace] = true
|
||||
return codespace
|
||||
}
|
||||
codespace++
|
||||
if codespace == MaximumCodespace {
|
||||
panic("Maximum codespace reached!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterOrPanic reserved a codespace or panics if it is unavailable
|
||||
func (c *Codespacer) RegisterOrPanic(codespace CodespaceType) {
|
||||
if c.reserved[codespace] {
|
||||
panic("Cannot register codespace, already reserved")
|
||||
}
|
||||
c.reserved[codespace] = true
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRegisterNext(t *testing.T) {
|
||||
codespacer := NewCodespacer()
|
||||
// unregistered, allow
|
||||
code1 := codespacer.RegisterNext(CodespaceType(2))
|
||||
require.Equal(t, code1, CodespaceType(2))
|
||||
// registered, pick next
|
||||
code2 := codespacer.RegisterNext(CodespaceType(2))
|
||||
require.Equal(t, code2, CodespaceType(3))
|
||||
// pick next
|
||||
code3 := codespacer.RegisterNext(CodespaceType(2))
|
||||
require.Equal(t, code3, CodespaceType(4))
|
||||
// skip 1
|
||||
code4 := codespacer.RegisterNext(CodespaceType(6))
|
||||
require.Equal(t, code4, CodespaceType(6))
|
||||
code5 := codespacer.RegisterNext(CodespaceType(2))
|
||||
require.Equal(t, code5, CodespaceType(5))
|
||||
code6 := codespacer.RegisterNext(CodespaceType(2))
|
||||
require.Equal(t, code6, CodespaceType(7))
|
||||
// panic on maximum
|
||||
defer func() {
|
||||
r := recover()
|
||||
require.NotNil(t, r, "Did not panic on maximum codespace")
|
||||
}()
|
||||
codespacer.RegisterNext(MaximumCodespace - 1)
|
||||
codespacer.RegisterNext(MaximumCodespace - 1)
|
||||
}
|
||||
|
||||
func TestRegisterOrPanic(t *testing.T) {
|
||||
codespacer := NewCodespacer()
|
||||
// unregistered, allow
|
||||
code1 := codespacer.RegisterNext(CodespaceType(2))
|
||||
require.Equal(t, code1, CodespaceType(2))
|
||||
// panic on duplicate
|
||||
defer func() {
|
||||
r := recover()
|
||||
require.NotNil(t, r, "Did not panic on duplicate codespace")
|
||||
}()
|
||||
codespacer.RegisterOrPanic(CodespaceType(2))
|
||||
}
|
||||
+14
-38
@@ -10,37 +10,22 @@ import (
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
// ABCICodeType - combined codetype / codespace
|
||||
type ABCICodeType uint32
|
||||
|
||||
// CodeType - code identifier within codespace
|
||||
type CodeType uint16
|
||||
// CodeType - ABCI code identifier within codespace
|
||||
type CodeType uint32
|
||||
|
||||
// CodespaceType - codespace identifier
|
||||
type CodespaceType uint16
|
||||
type CodespaceType string
|
||||
|
||||
// IsOK - is everything okay?
|
||||
func (code ABCICodeType) IsOK() bool {
|
||||
if code == ABCICodeOK {
|
||||
func (code CodeType) IsOK() bool {
|
||||
if code == CodeOK {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// get the abci code from the local code and codespace
|
||||
func ToABCICode(space CodespaceType, code CodeType) ABCICodeType {
|
||||
// TODO: Make Tendermint more aware of codespaces.
|
||||
if space == CodespaceRoot && code == CodeOK {
|
||||
return ABCICodeOK
|
||||
}
|
||||
return ABCICodeType((uint32(space) << 16) | uint32(code))
|
||||
}
|
||||
|
||||
// SDK error codes
|
||||
const (
|
||||
// ABCI error codes
|
||||
ABCICodeOK ABCICodeType = 0
|
||||
|
||||
// Base error codes
|
||||
CodeOK CodeType = 0
|
||||
CodeInternal CodeType = 1
|
||||
@@ -62,11 +47,8 @@ const (
|
||||
// CodespaceRoot is a codespace for error codes in this file only.
|
||||
// Notice that 0 is an "unset" codespace, which can be overridden with
|
||||
// Error.WithDefaultCodespace().
|
||||
CodespaceUndefined CodespaceType = 0
|
||||
CodespaceRoot CodespaceType = 1
|
||||
|
||||
// Maximum reservable codespace (2^16 - 1)
|
||||
MaximumCodespace CodespaceType = 65535
|
||||
CodespaceUndefined CodespaceType = ""
|
||||
CodespaceRoot CodespaceType = "sdk"
|
||||
)
|
||||
|
||||
func unknownCodeMsg(code CodeType) string {
|
||||
@@ -185,7 +167,6 @@ type Error interface {
|
||||
Code() CodeType
|
||||
Codespace() CodespaceType
|
||||
ABCILog() string
|
||||
ABCICode() ABCICodeType
|
||||
Result() Result
|
||||
QueryResult() abci.ResponseQuery
|
||||
}
|
||||
@@ -239,17 +220,12 @@ func (err *sdkError) TraceSDK(format string, args ...interface{}) Error {
|
||||
// Implements ABCIError.
|
||||
func (err *sdkError) Error() string {
|
||||
return fmt.Sprintf(`ERROR:
|
||||
Codespace: %d
|
||||
Codespace: %s
|
||||
Code: %d
|
||||
Message: %#v
|
||||
`, err.codespace, err.code, err.cmnError.Error())
|
||||
}
|
||||
|
||||
// Implements ABCIError.
|
||||
func (err *sdkError) ABCICode() ABCICodeType {
|
||||
return ToABCICode(err.codespace, err.code)
|
||||
}
|
||||
|
||||
// Implements Error.
|
||||
func (err *sdkError) Codespace() CodespaceType {
|
||||
return err.codespace
|
||||
@@ -267,7 +243,6 @@ func (err *sdkError) ABCILog() string {
|
||||
jsonErr := humanReadableError{
|
||||
Codespace: err.codespace,
|
||||
Code: err.code,
|
||||
ABCICode: err.ABCICode(),
|
||||
Message: errMsg,
|
||||
}
|
||||
bz, er := cdc.MarshalJSON(jsonErr)
|
||||
@@ -280,16 +255,18 @@ func (err *sdkError) ABCILog() string {
|
||||
|
||||
func (err *sdkError) Result() Result {
|
||||
return Result{
|
||||
Code: err.ABCICode(),
|
||||
Log: err.ABCILog(),
|
||||
Code: err.Code(),
|
||||
Codespace: err.Codespace(),
|
||||
Log: err.ABCILog(),
|
||||
}
|
||||
}
|
||||
|
||||
// QueryResult allows us to return sdk.Error.QueryResult() in query responses
|
||||
func (err *sdkError) QueryResult() abci.ResponseQuery {
|
||||
return abci.ResponseQuery{
|
||||
Code: uint32(err.ABCICode()),
|
||||
Log: err.ABCILog(),
|
||||
Code: uint32(err.Code()),
|
||||
Codespace: string(err.Codespace()),
|
||||
Log: err.ABCILog(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,6 +301,5 @@ func mustGetMsgIndex(abciLog string) int {
|
||||
type humanReadableError struct {
|
||||
Codespace CodespaceType `json:"codespace"`
|
||||
Code CodeType `json:"code"`
|
||||
ABCICode ABCICodeType `json:"abci_code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ var errFns = []errFn{
|
||||
}
|
||||
|
||||
func TestCodeType(t *testing.T) {
|
||||
require.True(t, ABCICodeOK.IsOK())
|
||||
require.True(t, CodeOK.IsOK())
|
||||
|
||||
for tcnum, c := range codeTypes {
|
||||
msg := CodeToDefaultMsg(c)
|
||||
@@ -59,12 +59,9 @@ func TestErrFn(t *testing.T) {
|
||||
codeType := codeTypes[i]
|
||||
require.Equal(t, err.Code(), codeType, "Err function expected to return proper code. tc #%d", i)
|
||||
require.Equal(t, err.Codespace(), CodespaceRoot, "Err function expected to return proper codespace. tc #%d", i)
|
||||
require.Equal(t, err.Result().Code, ToABCICode(CodespaceRoot, codeType), "Err function expected to return proper ABCICode. tc #%d")
|
||||
require.Equal(t, err.QueryResult().Code, uint32(err.ABCICode()), "Err function expected to return proper ABCICode from QueryResult. tc #%d")
|
||||
require.Equal(t, err.QueryResult().Code, uint32(err.Code()), "Err function expected to return proper Code from QueryResult. tc #%d")
|
||||
require.Equal(t, err.QueryResult().Log, err.ABCILog(), "Err function expected to return proper ABCILog from QueryResult. tc #%d")
|
||||
}
|
||||
|
||||
require.Equal(t, ABCICodeOK, ToABCICode(CodespaceRoot, CodeOK))
|
||||
}
|
||||
|
||||
func TestAppendMsgToErr(t *testing.T) {
|
||||
|
||||
+4
-1
@@ -4,7 +4,10 @@ package types
|
||||
type Result struct {
|
||||
|
||||
// Code is the response code, is stored back on the chain.
|
||||
Code ABCICodeType
|
||||
Code CodeType
|
||||
|
||||
// Codespace is the string referring to the domain of an error
|
||||
Codespace CodespaceType
|
||||
|
||||
// Data is any data returned from the app.
|
||||
Data []byte
|
||||
|
||||
@@ -13,6 +13,6 @@ func TestResult(t *testing.T) {
|
||||
res.Data = []byte("data")
|
||||
require.True(t, res.IsOK())
|
||||
|
||||
res.Code = ABCICodeType(1)
|
||||
res.Code = CodeType(1)
|
||||
require.False(t, res.IsOK())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user