Codespaces as Strings (#2821)

This commit is contained in:
Sunny Aggarwal
2018-11-16 09:12:24 -08:00
committed by Jae Kwon
parent ca2270c87e
commit 8d6b0929fb
39 changed files with 119 additions and 210 deletions
-35
View File
@@ -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
}
-47
View File
@@ -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
View File
@@ -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"`
}
+2 -5
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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())
}