Skip to content

Commit 398177c

Browse files
authored
Candidate Register & Update with BLS pubkey (#4686)
1 parent ebc64df commit 398177c

21 files changed

+858
-209
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ GOVET=$(GOCMD) vet
1111
GOBUILD=$(GOCMD) build
1212
GOINSTALL=$(GOCMD) install
1313
GOCLEAN=$(GOCMD) clean
14-
GOTEST=GOARCH=amd64 CGO_ENABLED=1 $(GOCMD) test
14+
GOTEST=CGO_ENABLED=1 $(GOCMD) test
1515
GOGET=$(GOCMD) get
1616
GOPATH=$(shell go env GOPATH)
1717
BUILD_TARGET_SERVER=server

action/builder.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ func (b *EnvelopeBuilder) BuildStakingAction(tx *types.Transaction) (Envelope, e
259259
if err := b.setEnvelopeCommonFields(tx); err != nil {
260260
return nil, err
261261
}
262-
act, err := newStakingActionFromABIBinary(tx.Data())
262+
act, err := newStakingActionFromABIBinary(tx.Data(), tx.Value())
263263
if err != nil {
264264
return nil, err
265265
}
@@ -283,7 +283,7 @@ func (b *EnvelopeBuilder) BuildRewardingAction(tx *types.Transaction) (Envelope,
283283
return b.build(), nil
284284
}
285285

286-
func newStakingActionFromABIBinary(data []byte) (actionPayload, error) {
286+
func newStakingActionFromABIBinary(data []byte, value *big.Int) (actionPayload, error) {
287287
if len(data) <= 4 {
288288
return nil, ErrInvalidABI
289289
}
@@ -308,7 +308,7 @@ func newStakingActionFromABIBinary(data []byte) (actionPayload, error) {
308308
if act, err := NewTransferStakeFromABIBinary(data); err == nil {
309309
return act, nil
310310
}
311-
if act, err := NewCandidateRegisterFromABIBinary(data); err == nil {
311+
if act, err := NewCandidateRegisterFromABIBinary(data, value); err == nil {
312312
return act, nil
313313
}
314314
if act, err := NewCandidateUpdateFromABIBinary(data); err == nil {

action/candidate_register.go

Lines changed: 202 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111

1212
"github.com/ethereum/go-ethereum/accounts/abi"
1313
"github.com/ethereum/go-ethereum/common"
14+
"github.com/iotexproject/go-pkgs/crypto"
15+
"github.com/iotexproject/go-pkgs/hash"
1416
"github.com/iotexproject/iotex-address/address"
1517
"github.com/iotexproject/iotex-proto/golang/iotextypes"
1618
"github.com/pkg/errors"
@@ -28,7 +30,11 @@ const (
2830

2931
var (
3032
// _candidateRegisterInterface is the interface of the abi encoding of stake action
31-
_candidateRegisterMethod abi.Method
33+
_candidateRegisterMethod abi.Method
34+
_candidateRegisterWithBLSMethod abi.Method
35+
_candidateRegisteredEvent abi.Event
36+
_stakedEvent abi.Event
37+
_candidateActivatedEvent abi.Event
3238

3339
// ErrInvalidAmount represents that amount is 0 or negative
3440
ErrInvalidAmount = errors.New("invalid amount")
@@ -39,6 +45,9 @@ var (
3945
// ErrInvalidOwner represents that owner address is invalid
4046
ErrInvalidOwner = errors.New("invalid owner address")
4147

48+
// ErrInvalidBLSPubKey represents that BLS public key is invalid
49+
ErrInvalidBLSPubKey = errors.New("invalid BLS public key")
50+
4251
_ EthCompatibleAction = (*CandidateRegister)(nil)
4352
_ amountForCost = (*CandidateRegister)(nil)
4453
)
@@ -54,6 +63,7 @@ type CandidateRegister struct {
5463
duration uint32
5564
autoStake bool
5665
payload []byte
66+
pubKey []byte // BLS public key
5767
}
5868

5969
func init() {
@@ -62,6 +72,22 @@ func init() {
6272
if !ok {
6373
panic("fail to load the method")
6474
}
75+
_candidateRegisterWithBLSMethod, ok = NativeStakingContractABI().Methods["candidateRegisterWithBLS"]
76+
if !ok {
77+
panic("fail to load the method")
78+
}
79+
_candidateRegisteredEvent, ok = NativeStakingContractABI().Events["CandidateRegistered"]
80+
if !ok {
81+
panic("fail to load the event")
82+
}
83+
_stakedEvent, ok = NativeStakingContractABI().Events["Staked"]
84+
if !ok {
85+
panic("fail to load the event")
86+
}
87+
_candidateActivatedEvent, ok = NativeStakingContractABI().Events["CandidateActivated"]
88+
if !ok {
89+
panic("fail to load the event")
90+
}
6591
}
6692

6793
// NewCandidateRegister creates a CandidateRegister instance
@@ -106,8 +132,18 @@ func NewCandidateRegister(
106132
return cr, nil
107133
}
108134

135+
// LegacyAmount returns the legacy amount
136+
func (cr *CandidateRegister) LegacyAmount() *big.Int {
137+
return cr.amount
138+
}
139+
109140
// Amount returns the amount
110-
func (cr *CandidateRegister) Amount() *big.Int { return cr.amount }
141+
func (cr *CandidateRegister) Amount() *big.Int {
142+
if cr.WithBLS() {
143+
return cr.value
144+
}
145+
return cr.amount
146+
}
111147

112148
// Payload returns the payload bytes
113149
func (cr *CandidateRegister) Payload() []byte { return cr.payload }
@@ -130,6 +166,16 @@ func (cr *CandidateRegister) RewardAddress() address.Address { return cr.rewardA
130166
// OwnerAddress returns candidate ownerAddress to register
131167
func (cr *CandidateRegister) OwnerAddress() address.Address { return cr.ownerAddress }
132168

169+
// WithBLS returns true if the candidate register action is with BLS public key
170+
func (cr *CandidateRegister) WithBLS() bool {
171+
return len(cr.pubKey) > 0
172+
}
173+
174+
// PubKey returns the BLS public key if the candidate register action is with BLS public key
175+
func (cr *CandidateRegister) PubKey() []byte {
176+
return cr.pubKey
177+
}
178+
133179
// Serialize returns a raw byte stream of the CandidateRegister struct
134180
func (cr *CandidateRegister) Serialize() []byte {
135181
return byteutil.Must(proto.Marshal(cr.Proto()))
@@ -151,10 +197,6 @@ func (cr *CandidateRegister) Proto() *iotextypes.CandidateRegister {
151197
AutoStake: cr.autoStake,
152198
}
153199

154-
if cr.amount != nil {
155-
act.StakedAmount = cr.amount.String()
156-
}
157-
158200
if cr.ownerAddress != nil {
159201
act.OwnerAddress = cr.ownerAddress.String()
160202
}
@@ -163,6 +205,20 @@ func (cr *CandidateRegister) Proto() *iotextypes.CandidateRegister {
163205
act.Payload = make([]byte, len(cr.payload))
164206
copy(act.Payload, cr.payload)
165207
}
208+
209+
switch {
210+
case cr.WithBLS():
211+
act.Candidate.PubKey = make([]byte, len(cr.pubKey))
212+
copy(act.Candidate.PubKey, cr.pubKey)
213+
if cr.value != nil {
214+
act.StakedAmount = cr.value.String()
215+
}
216+
default:
217+
if cr.amount != nil {
218+
act.StakedAmount = cr.amount.String()
219+
}
220+
}
221+
166222
return &act
167223
}
168224

@@ -189,11 +245,21 @@ func (cr *CandidateRegister) LoadProto(pbAct *iotextypes.CandidateRegister) erro
189245
cr.duration = pbAct.GetStakedDuration()
190246
cr.autoStake = pbAct.GetAutoStake()
191247

248+
withBLS := len(pbAct.Candidate.GetPubKey()) > 0
249+
if withBLS {
250+
cr.pubKey = make([]byte, len(pbAct.Candidate.GetPubKey()))
251+
copy(cr.pubKey, pbAct.Candidate.GetPubKey())
252+
}
192253
if len(pbAct.GetStakedAmount()) > 0 {
193-
var ok bool
194-
if cr.amount, ok = new(big.Int).SetString(pbAct.GetStakedAmount(), 10); !ok {
254+
amount, ok := new(big.Int).SetString(pbAct.GetStakedAmount(), 10)
255+
if !ok {
195256
return errors.Errorf("invalid amount %s", pbAct.GetStakedAmount())
196257
}
258+
if withBLS {
259+
cr.value = amount
260+
} else {
261+
cr.amount = amount
262+
}
197263
}
198264

199265
cr.payload = nil
@@ -209,6 +275,7 @@ func (cr *CandidateRegister) LoadProto(pbAct *iotextypes.CandidateRegister) erro
209275
}
210276
cr.ownerAddress = ownerAddr
211277
}
278+
212279
return nil
213280
}
214281

@@ -240,34 +307,127 @@ func (cr *CandidateRegister) EthData() ([]byte, error) {
240307
if cr.ownerAddress == nil {
241308
return nil, ErrAddress
242309
}
243-
data, err := _candidateRegisterMethod.Inputs.Pack(
244-
cr.name,
245-
common.BytesToAddress(cr.operatorAddress.Bytes()),
246-
common.BytesToAddress(cr.rewardAddress.Bytes()),
247-
common.BytesToAddress(cr.ownerAddress.Bytes()),
248-
cr.amount,
249-
cr.duration,
250-
cr.autoStake,
251-
cr.payload)
310+
switch {
311+
case cr.WithBLS():
312+
data, err := _candidateRegisterWithBLSMethod.Inputs.Pack(
313+
cr.name,
314+
common.BytesToAddress(cr.operatorAddress.Bytes()),
315+
common.BytesToAddress(cr.rewardAddress.Bytes()),
316+
common.BytesToAddress(cr.ownerAddress.Bytes()),
317+
cr.amount,
318+
cr.duration,
319+
cr.autoStake,
320+
cr.pubKey,
321+
cr.payload)
322+
if err != nil {
323+
return nil, err
324+
}
325+
return append(_candidateRegisterMethod.ID, data...), nil
326+
default:
327+
data, err := _candidateRegisterMethod.Inputs.Pack(
328+
cr.name,
329+
common.BytesToAddress(cr.operatorAddress.Bytes()),
330+
common.BytesToAddress(cr.rewardAddress.Bytes()),
331+
common.BytesToAddress(cr.ownerAddress.Bytes()),
332+
cr.amount,
333+
cr.duration,
334+
cr.autoStake,
335+
cr.payload)
336+
if err != nil {
337+
return nil, err
338+
}
339+
return append(_candidateRegisterMethod.ID, data...), nil
340+
}
341+
}
342+
343+
// PackCandidateRegisteredEvent packs the CandidateRegisterWithBLS event
344+
func PackCandidateRegisteredEvent(
345+
candidate,
346+
operatorAddress,
347+
ownerAddress address.Address,
348+
name string,
349+
rewardAddress address.Address,
350+
blsPublicKey []byte,
351+
) (Topics, []byte, error) {
352+
data, err := _candidateRegisteredEvent.Inputs.NonIndexed().Pack(
353+
operatorAddress.Bytes(),
354+
name,
355+
rewardAddress.Bytes(),
356+
blsPublicKey,
357+
)
252358
if err != nil {
253-
return nil, err
359+
return nil, nil, errors.Wrap(err, "failed to pack CandidateRegisterWithBLS event")
360+
}
361+
topics := make(Topics, 3)
362+
topics[0] = hash.Hash256(_candidateRegisteredEvent.ID)
363+
topics[1] = hash.Hash256(candidate.Bytes())
364+
topics[2] = hash.Hash256(ownerAddress.Bytes())
365+
return topics, data, nil
366+
}
367+
368+
func PackStakedEvent(
369+
voter,
370+
candidate address.Address,
371+
bucketIndex uint64,
372+
amount *big.Int,
373+
duration uint32,
374+
autoStake bool) (Topics, []byte, error) {
375+
data, err := _stakedEvent.Inputs.NonIndexed().Pack(
376+
bucketIndex,
377+
amount,
378+
duration,
379+
autoStake,
380+
)
381+
if err != nil {
382+
return nil, nil, errors.Wrap(err, "failed to pack Staked event")
383+
}
384+
topics := make(Topics, 3)
385+
topics[0] = hash.Hash256(_stakedEvent.ID)
386+
topics[1] = hash.Hash256(voter.Bytes())
387+
topics[2] = hash.Hash256(candidate.Bytes())
388+
return topics, data, nil
389+
}
390+
391+
func PackCandidateActivatedEvent(
392+
candidate address.Address, bucketIndex uint64,
393+
) (Topics, []byte, error) {
394+
data, err := _candidateActivatedEvent.Inputs.NonIndexed().Pack(
395+
bucketIndex,
396+
)
397+
if err != nil {
398+
return nil, nil, errors.Wrap(err, "failed to pack CandidateActivated event")
254399
}
255-
return append(_candidateRegisterMethod.ID, data...), nil
400+
topics := make(Topics, 2)
401+
topics[0] = hash.Hash256(_candidateActivatedEvent.ID)
402+
topics[1] = hash.Hash256(candidate.Bytes())
403+
return topics, data, nil
256404
}
257405

258406
// NewCandidateRegisterFromABIBinary decodes data into CandidateRegister action
259-
func NewCandidateRegisterFromABIBinary(data []byte) (*CandidateRegister, error) {
407+
func NewCandidateRegisterFromABIBinary(data []byte, value *big.Int) (*CandidateRegister, error) {
260408
var (
261409
paramsMap = map[string]interface{}{}
262410
ok bool
263411
err error
264412
cr CandidateRegister
413+
method abi.Method
414+
withBLS bool
265415
)
266416
// sanity check
267-
if len(data) <= 4 || !bytes.Equal(_candidateRegisterMethod.ID, data[:4]) {
417+
if len(data) <= 4 {
268418
return nil, errDecodeFailure
269419
}
270-
if err := _candidateRegisterMethod.Inputs.UnpackIntoMap(paramsMap, data[4:]); err != nil {
420+
switch {
421+
case bytes.Equal(_candidateRegisterMethod.ID, data[:4]):
422+
method = _candidateRegisterMethod
423+
case bytes.Equal(_candidateRegisterWithBLSMethod.ID, data[:4]):
424+
method = _candidateRegisterWithBLSMethod
425+
withBLS = true
426+
default:
427+
return nil, errDecodeFailure
428+
}
429+
// common fields parsing
430+
if err := method.Inputs.UnpackIntoMap(paramsMap, data[4:]); err != nil {
271431
return nil, err
272432
}
273433
if cr.name, ok = paramsMap["name"].(string); !ok {
@@ -282,9 +442,6 @@ func NewCandidateRegisterFromABIBinary(data []byte) (*CandidateRegister, error)
282442
if cr.ownerAddress, err = ethAddrToNativeAddr(paramsMap["ownerAddress"]); err != nil {
283443
return nil, err
284444
}
285-
if cr.amount, ok = paramsMap["amount"].(*big.Int); !ok {
286-
return nil, errDecodeFailure
287-
}
288445
if cr.duration, ok = paramsMap["duration"].(uint32); !ok {
289446
return nil, errDecodeFailure
290447
}
@@ -294,6 +451,26 @@ func NewCandidateRegisterFromABIBinary(data []byte) (*CandidateRegister, error)
294451
if cr.payload, ok = paramsMap["data"].([]byte); !ok {
295452
return nil, errDecodeFailure
296453
}
454+
// specific fields parsing for methods
455+
if withBLS {
456+
if value != nil {
457+
cr.value.Set(value)
458+
}
459+
if cr.pubKey, ok = paramsMap["pubKey"].([]byte); !ok {
460+
return nil, errors.Wrapf(errDecodeFailure, "invalid pubKey %+v", paramsMap["pubKey"])
461+
}
462+
if len(cr.pubKey) == 0 {
463+
return nil, errors.Wrap(errDecodeFailure, "pubKey is empty")
464+
}
465+
_, err := crypto.BLS12381PublicKeyFromBytes(cr.pubKey)
466+
if err != nil {
467+
return nil, errors.Wrap(err, "failed to parse BLS public key")
468+
}
469+
} else {
470+
if cr.amount, ok = paramsMap["amount"].(*big.Int); !ok {
471+
return nil, errDecodeFailure
472+
}
473+
}
297474
return &cr, nil
298475
}
299476

0 commit comments

Comments
 (0)