forked from hyperledger-archives/burrow
-
Notifications
You must be signed in to change notification settings - Fork 0
/
address.go
197 lines (165 loc) · 4.73 KB
/
address.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
package crypto
import (
"bytes"
"encoding/json"
"fmt"
"github.com/hyperledger/burrow/binary"
"github.com/tmthrgd/go-hex"
"golang.org/x/crypto/ripemd160"
)
type Addressable interface {
// Get the 20 byte EVM address of this account
GetAddress() Address
// Public key from which the Address is derived
GetPublicKey() PublicKey
}
func NewAddressable(publicKey PublicKey) Addressable {
return &memoizedAddressable{
address: publicKey.GetAddress(),
publicKey: publicKey,
}
}
type memoizedAddressable struct {
publicKey PublicKey
address Address
}
func MemoizeAddressable(addressable Addressable) Addressable {
if a, ok := addressable.(*memoizedAddressable); ok {
return a
}
return NewAddressable(addressable.GetPublicKey())
}
func (a *memoizedAddressable) GetPublicKey() PublicKey {
return a.publicKey
}
func (a *memoizedAddressable) GetAddress() Address {
return a.address
}
type Address binary.Word160
type Addresses []Address
func (as Addresses) Len() int {
return len(as)
}
func (as Addresses) Less(i, j int) bool {
return bytes.Compare(as[i][:], as[j][:]) < 0
}
func (as Addresses) Swap(i, j int) {
as[i], as[j] = as[j], as[i]
}
const AddressLength = binary.Word160Length
const AddressHexLength = 2 * AddressLength
var ZeroAddress = Address{}
// Returns a pointer to an Address that is nil iff len(bs) == 0 otherwise does the same as AddressFromBytes
func MaybeAddressFromBytes(bs []byte) (*Address, error) {
if len(bs) == 0 {
return nil, nil
}
address, err := AddressFromBytes(bs)
if err != nil {
return nil, err
}
return &address, nil
}
// Returns an address consisting of the first 20 bytes of bs, return an error if the bs does not have length exactly 20
// but will still return either: the bytes in bs padded on the right or the first 20 bytes of bs truncated in any case.
func AddressFromBytes(bs []byte) (address Address, err error) {
if len(bs) != binary.Word160Length {
err = fmt.Errorf("slice passed as address '%X' has %d bytes but should have %d bytes",
bs, len(bs), binary.Word160Length)
// It is caller's responsibility to check for errors. If they ignore the error we'll assume they want the
// best-effort mapping of the bytes passed to an address so we don't return here
}
copy(address[:], bs)
return
}
func AddressFromHexString(str string) (Address, error) {
bs, err := hex.DecodeString(str)
if err != nil {
return ZeroAddress, err
}
return AddressFromBytes(bs)
}
func MustAddressFromBytes(addr []byte) Address {
address, err := AddressFromBytes(addr)
if err != nil {
panic(fmt.Errorf("error reading address from bytes that caller does not expect: %s", err))
}
return address
}
func AddressFromWord256(addr binary.Word256) Address {
return Address(addr.Word160())
}
func (address Address) Word256() binary.Word256 {
return binary.Word160(address).Word256()
}
// Copy address and return a slice onto the copy
func (address Address) Bytes() []byte {
addressCopy := address
return addressCopy[:]
}
func (address Address) String() string {
return hex.EncodeUpperToString(address[:])
}
func (address *Address) UnmarshalJSON(data []byte) error {
str := new(string)
err := json.Unmarshal(data, str)
if err != nil {
return err
}
err = address.UnmarshalText([]byte(*str))
if err != nil {
return err
}
return nil
}
func (address Address) MarshalJSON() ([]byte, error) {
text, err := address.MarshalText()
if err != nil {
return nil, err
}
return json.Marshal(string(text))
}
func (address *Address) UnmarshalText(text []byte) error {
if len(text) != AddressHexLength {
return fmt.Errorf("address hex '%s' has length %v but must have length %v to be a valid address",
string(text), len(text), AddressHexLength)
}
_, err := hex.Decode(address[:], text)
return err
}
func (address Address) MarshalText() ([]byte, error) {
return ([]byte)(hex.EncodeUpperToString(address[:])), nil
}
// Gogo proto support
func (address *Address) Marshal() ([]byte, error) {
if address == nil {
return nil, nil
}
return address.Bytes(), nil
}
func (address *Address) Unmarshal(data []byte) error {
if len(data) == 0 {
return nil
}
if len(data) != binary.Word160Length {
return fmt.Errorf("error unmarshallling address '%X' from bytes: %d bytes but should have %d bytes",
data, len(data), binary.Word160Length)
}
copy(address[:], data)
return nil
}
func (address *Address) MarshalTo(data []byte) (int, error) {
return copy(data, address[:]), nil
}
func (address *Address) Size() int {
return binary.Word160Length
}
func NewContractAddress(caller Address, sequence uint64) (newAddr Address) {
temp := make([]byte, 32+8)
copy(temp, caller[:])
binary.PutUint64BE(temp[32:], uint64(sequence))
hasher := ripemd160.New()
hasher.Write(temp) // does not error
copy(newAddr[:], hasher.Sum(nil))
return
}