@@ -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
2931var (
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" )
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
5969func 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
113149func (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
131167func (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
134180func (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