forked from cosmos/cosmos-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
context.go
109 lines (92 loc) · 2.68 KB
/
context.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package sdk
import (
"bytes"
"fmt"
"sort"
wire "github.com/tendermint/go-wire"
"github.com/tendermint/go-wire/data"
"github.com/tendermint/tmlibs/log"
)
// Actor abstracts any address that can authorize actions, hold funds,
// or initiate any sort of transaction.
//
// It doesn't just have to be a pubkey on this chain, it could stem from
// another app (like multi-sig account), or even another chain (via IBC)
type Actor struct {
ChainID string `json:"chain"` // this is empty unless it comes from a different chain
App string `json:"app"` // the app that the actor belongs to
Address data.Bytes `json:"addr"` // arbitrary app-specific unique id
}
// NewActor - create a new actor
func NewActor(app string, addr []byte) Actor {
return Actor{App: app, Address: addr}
}
// Bytes makes a binary coding, useful for turning this into a key in the store
func (a Actor) Bytes() []byte {
return wire.BinaryBytes(a)
}
// Equals checks if two actors are the same
func (a Actor) Equals(b Actor) bool {
return a.ChainID == b.ChainID &&
a.App == b.App &&
bytes.Equal(a.Address, b.Address)
}
// Empty checks if the actor is not initialized
func (a Actor) Empty() bool {
return a.ChainID == "" && a.App == "" && len(a.Address) == 0
}
// WithChain creates a copy of the actor with a different chainID
func (a Actor) WithChain(chainID string) (b Actor) {
b = a
b.ChainID = chainID
return
}
type Actors []Actor
func (a Actors) AllHaveChain(chainID string) bool {
for _, b := range a {
if b.ChainID != chainID {
return false
}
}
return true
}
// Context is an interface, so we can implement "secure" variants that
// rely on private fields to control the actions
type Context interface {
// context.Context
log.Logger
WithPermissions(perms ...Actor) Context
HasPermission(perm Actor) bool
GetPermissions(chain, app string) []Actor
IsParent(ctx Context) bool
Reset() Context
ChainID() string
BlockHeight() uint64
}
//////////////////////////////// Sort Interface
// USAGE sort.Sort(ByAll(<actor instance>))
func (a Actor) String() string {
return fmt.Sprintf("%x", a.Address)
}
// ByAll implements sort.Interface for []Actor.
// It sorts be the ChainID, followed by the App, followed by the Address
type ByAll []Actor
// Verify the sort interface at compile time
var _ sort.Interface = ByAll{}
func (a ByAll) Len() int { return len(a) }
func (a ByAll) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByAll) Less(i, j int) bool {
if a[i].ChainID < a[j].ChainID {
return true
}
if a[i].ChainID > a[j].ChainID {
return false
}
if a[i].App < a[j].App {
return true
}
if a[i].App > a[j].App {
return false
}
return bytes.Compare(a[i].Address, a[j].Address) == -1
}