diff --git a/tests/data/era/era_summary_v2_delegator_kind_purse.json b/tests/data/era/era_summary_v2_delegator_kind_purse.json new file mode 100644 index 0000000..91d6644 --- /dev/null +++ b/tests/data/era/era_summary_v2_delegator_kind_purse.json @@ -0,0 +1,69 @@ +{ + "block_hash": "34f7c0246c6dd3b4ae7161a59c6834a9aaa12f74b8d2c4d16ec347a9b8a90407", + "era_id": 15383, + "stored_value": { + "EraInfo": { + "seigniorage_allocations": [ + { + "Validator": { + "validator_public_key": "01032146b0b9de01e26aaec7b0d1769920de94681dbd432c3530bfe591752ded6c", + "amount": "100542274855185" + } + }, + { + "Validator": { + "validator_public_key": "01032146b0b9de01e26aaec7b0d1769920de94681dbd432c3530bfe591752ded6c", + "amount": "84485499521" + } + }, + { + "Validator": { + "validator_public_key": "0126d4637eb0c0769274f03a696df1112383fa621c9f73f57af4c5c0fbadafa8cf", + "amount": "88379190136305" + } + }, + { + "Validator": { + "validator_public_key": "0126d4637eb0c0769274f03a696df1112383fa621c9f73f57af4c5c0fbadafa8cf", + "amount": "84493160372" + } + }, + { + "Validator": { + "validator_public_key": "0140afe8f752e5ff100e0189c080bc207e8805b3e5e82f792ec608de2f11f39f6c", + "amount": "99527758907914" + } + }, + { + "Validator": { + "validator_public_key": "0140afe8f752e5ff100e0189c080bc207e8805b3e5e82f792ec608de2f11f39f6c", + "amount": "84483913675" + } + }, + { + "Validator": { + "validator_public_key": "017536433a73f7562526f3e9fcb8d720428ae2d28788a9909f3c6f637a9d848a4b", + "amount": "83817182779548" + } + }, + { + "Validator": { + "validator_public_key": "017536433a73f7562526f3e9fcb8d720428ae2d28788a9909f3c6f637a9d848a4b", + "amount": "84494615864" + } + }, + { + "Delegator": { + "delegator_kind": { + "Purse": "de0ef381c12dc842e0872453d35aa4b49fa488c0427e68b7dd5ac63e151eae98" + }, + "validator_public_key": "01197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "amount": "1000000000" + } + } + ] + } + }, + "state_root_hash": "6e8ed1a812f9518ee39277f77f707955a3f73b2c775df7424b2da175625b8f2e", + "merkle_proof": "010000000b000000000000000000000000000000000000000000000000000000000000000007080000000001032146b0b9de01e26aaec7b0d1769920de94681dbd432c3530bfe591752ded6c0611e19352715b0001032146b0b9de01e26aaec7b0d1769920de94681dbd432c3530bfe591752ded6c05816abaab13000126d4637eb0c0769274f03a696df1112383fa621c9f73f57af4c5c0fbadafa8cf06f1cd3b626150000126d4637eb0c0769274f03a696df1112383fa621c9f73f57af4c5c0fbadafa8cf05b44f2fac13000140afe8f752e5ff100e0189c080bc207e8805b3e5e82f792ec608de2f11f39f6c060a0ab71c855a000140afe8f752e5ff100e0189c080bc207e8805b3e5e82f792ec608de2f11f39f6c05cb37a2ab1300017536433a73f7562526f3e9fcb8d720428ae2d28788a9909f3c6f637a9d848a4b069cd867353b4c00017536433a73f7562526f3e9fcb8d720428ae2d28788a9909f3c6f637a9d848a4b05388545ac1301000000000b140000000001510e5f331b1a84b14252fe3913d3afb152f287462714c108b2cd03c29164207801018eb48c820fb106611a9dc65b5516c76267c7a546c8b0f7f87ccad67dc1afa1f50201d39dc1d39d36b8c59e9355cdd55adf4d769cc6d63db915fe69ea94a24e8454840301a86c2de6d91155a59adda00169c1372f409b8e71aca5ecc95888e75ab4df366e0401744d6727bd6c08d70a1d49fa3fcb0397230595e628ed0c52f5a78d3d59c6cdbb06014bcefe3ed7eb0d929ffb1b06975df2caf7476f9beb3b0828be78fd766730668d0801732d8be21ba8d9d166007384999a8f4887b01534151e5d22a1f388be99412fc409018b587e1127177e34a3e470c3bc536da9f89345f0bcfdeb6b548be732d984d82c0a00aa359968ebc13aeb0ec170d86c230e35d478037aa4cc1441b186501323f5d9c90d00d133641314a03c3da85597bc23aaa10b56ecc43efc1035c69d76463cecb633a00e0043d39741a6e7b395eace3b1fbbbd5bbf288f7a788e80745a2e2bb0f2173a8b4f0f018e1ee0db6abadb25182adb757ee0fb68645c62892c43bdb5f66f04ddd49c26db1001d515393ea4ba786b0a887b03406e563b8bb6eec7130c2b74af11c301edb19242110177049afcfe3f07f8fb1ff429073573fd537ec93a14c0aaad71141afaac088093120176706b834e9776d305d9d5face0a7c273a646827ffc02c4f0fdf92192767ca3b1301b86fb4cf28dec81b269a278ed437302f10921d86fe16a4de0e0240f735ee8f5d1401e127033e641533f0ee99f0612c9e20c86e9c1974aada7e03af57ae81ef58c09b1501d789c8bba61eab50b62479a596b99f4268f8ae0a4c770e71ab75ed870b6ecda1160109ee69158b030e49dd6f79b65ea0dea62cca0df0163c7b08dc7379ac2e5265a91701ccc91d447ba4fa1d39e26b2e4c45cee12291790d0e54d95ce0c71ce798cc02de" +} diff --git a/tests/data/transaction/get_transaction_with_delegator_kind.json b/tests/data/transaction/get_transaction_with_delegator_kind.json new file mode 100644 index 0000000..e4057b2 --- /dev/null +++ b/tests/data/transaction/get_transaction_with_delegator_kind.json @@ -0,0 +1,251 @@ +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "api_version": "2.0.0", + "transaction": { + "Version1": { + "hash": "67594388afce12d027d2098f0bee6742702738647fb8d422d85f1b2c8b72192c", + "payload": { + "initiator_addr": { + "PublicKey": "015adadaecbd299c594821a548d755f51a5e2124fb17983f9afae019add32beb21" + }, + "timestamp": "2024-12-04T14:54:15.400Z", + "ttl": "30m", + "chain_name": "casper-net-1", + "pricing_mode": { + "Fixed": { + "additional_computation_factor": 1, + "gas_price_tolerance": 1 + } + }, + "fields": { + "args": { + "Named": [ + [ + "delegator_purse", + { + "cl_type": "URef", + "bytes": "de0ef381c12dc842e0872453d35aa4b49fa488c0427e68b7dd5ac63e151eae9807", + "parsed": "uref-de0ef381c12dc842e0872453d35aa4b49fa488c0427e68b7dd5ac63e151eae98-007" + } + ], + [ + "amount", + { + "cl_type": "U512", + "bytes": "0500282e8cd1", + "parsed": "900000000000" + } + ], + [ + "validator", + { + "cl_type": "PublicKey", + "bytes": "01fed662dc7f1f7af43ad785ba07a8cc05b7a96f9ee69613cfde43bc56bec1140b", + "parsed": "01fed662dc7f1f7af43ad785ba07a8cc05b7a96f9ee69613cfde43bc56bec1140b" + } + ] + ] + }, + "entry_point": { + "Custom": "delegate" + }, + "scheduling": "Standard", + "target": { + "Stored": { + "id": { + "ByHash": "d39b360530484c6b3ed32e84a1198b368fe2bae3d5c9e8af6b0ae4d3eba73caa" + }, + "runtime": "VmCasperV1", + "transferred_value": 0 + } + } + } + }, + "approvals": [ + { + "signer": "015adadaecbd299c594821a548d755f51a5e2124fb17983f9afae019add32beb21", + "signature": "01dca399075db422c9d55976b050ef5cd221eae8a74b4dc0940d44d44c3c8743ca016f983491125e77f0e20a0aef2c1b7102c429141b5254536d453032a0f5c90a" + } + ] + } + }, + "execution_info": { + "block_hash": "c6d3dfe57580def4a7ccb0a2bacb294f4ef10dc392de2e7d845a8b76057f0f87", + "block_height": 11, + "execution_result": { + "Version2": { + "initiator": { + "PublicKey": "015adadaecbd299c594821a548d755f51a5e2124fb17983f9afae019add32beb21" + }, + "error_message": null, + "limit": "50000000000", + "consumed": "2500000000", + "cost": "50000000000", + "transfers": [ + { + "Version2": { + "transaction_hash": { + "Version1": "67594388afce12d027d2098f0bee6742702738647fb8d422d85f1b2c8b72192c" + }, + "from": { + "AccountHash": "account-hash-cdda4c2ed893a1ba91274237ea101030adb7283ecaab2441941a7fe8100cc631" + }, + "to": "account-hash-6174cf2e6f8fed1715c9a3bace9c50bfe572eecb763b0ed3f644532616452008", + "source": "uref-de0ef381c12dc842e0872453d35aa4b49fa488c0427e68b7dd5ac63e151eae98-002", + "target": "uref-94de0e38671dcf5f328134eecec56bb8349ad6ab575521ecb4ac6994eae9f638-007", + "amount": "900000000000", + "gas": "100000000", + "id": null + } + } + ], + "size_estimate": 624, + "effects": [ + { + "key": "balance-hold-01de0ef381c12dc842e0872453d35aa4b49fa488c0427e68b7dd5ac63e151eae9868292a9293010000", + "kind": { + "Write": { + "CLValue": { + "cl_type": "U512", + "bytes": "0500743ba40b", + "parsed": "50000000000" + } + } + } + }, + { + "key": "hash-d39b360530484c6b3ed32e84a1198b368fe2bae3d5c9e8af6b0ae4d3eba73caa", + "kind": "Identity" + }, + { + "key": "hash-8624f469c59e96f525abe85e9224440160d51ba1b46c641b947097fb8bfbbf06", + "kind": "Identity" + }, + { + "key": "bid-addr-012f3fb80d362ad0a922f446915a259c9aaec9ba99292b3e50ff2359c458007309", + "kind": "Identity" + }, + { + "key": "hash-2a9716d5916c2e581648cc0a030870af60df4ecbf891d179a334ee8ff1fd7b99", + "kind": "Identity" + }, + { + "key": "hash-65b22b950127083ee0aa9e669c7c97534cd4825259fe480046043eb16c3146a5", + "kind": "Identity" + }, + { + "key": "uref-94de0e38671dcf5f328134eecec56bb8349ad6ab575521ecb4ac6994eae9f638-000", + "kind": { + "Write": { + "CLValue": { + "cl_type": "Unit", + "bytes": "", + "parsed": null + } + } + } + }, + { + "key": "balance-94de0e38671dcf5f328134eecec56bb8349ad6ab575521ecb4ac6994eae9f638", + "kind": { + "Write": { + "CLValue": { + "cl_type": "U512", + "bytes": "00", + "parsed": "0" + } + } + } + }, + { + "key": "hash-2a9716d5916c2e581648cc0a030870af60df4ecbf891d179a334ee8ff1fd7b99", + "kind": "Identity" + }, + { + "key": "hash-65b22b950127083ee0aa9e669c7c97534cd4825259fe480046043eb16c3146a5", + "kind": "Identity" + }, + { + "key": "balance-hold-01de0ef381c12dc842e0872453d35aa4b49fa488c0427e68b7dd5ac63e151eae9868292a9293010000", + "kind": "Identity" + }, + { + "key": "balance-de0ef381c12dc842e0872453d35aa4b49fa488c0427e68b7dd5ac63e151eae98", + "kind": { + "Write": { + "CLValue": { + "cl_type": "U512", + "bytes": "0e00d8d173385ac138938d44c64d31", + "parsed": "999999999999999999999100000000000" + } + } + } + }, + { + "key": "balance-94de0e38671dcf5f328134eecec56bb8349ad6ab575521ecb4ac6994eae9f638", + "kind": { + "AddUInt512": "900000000000" + } + }, + { + "key": "bid-addr-032f3fb80d362ad0a922f446915a259c9aaec9ba99292b3e50ff2359c458007309de0ef381c12dc842e0872453d35aa4b49fa488c0427e68b7dd5ac63e151eae98", + "kind": { + "Write": { + "BidKind": { + "Delegator": { + "delegator_kind": { + "Purse": "de0ef381c12dc842e0872453d35aa4b49fa488c0427e68b7dd5ac63e151eae98" + }, + "staked_amount": "900000000000", + "bonding_purse": "uref-94de0e38671dcf5f328134eecec56bb8349ad6ab575521ecb4ac6994eae9f638-007", + "validator_public_key": "01fed662dc7f1f7af43ad785ba07a8cc05b7a96f9ee69613cfde43bc56bec1140b", + "vesting_schedule": null + } + } + } + } + }, + { + "key": "balance-hold-01de0ef381c12dc842e0872453d35aa4b49fa488c0427e68b7dd5ac63e151eae9868292a9293010000", + "kind": { + "Prune": "balance-hold-01de0ef381c12dc842e0872453d35aa4b49fa488c0427e68b7dd5ac63e151eae9868292a9293010000" + } + }, + { + "key": "balance-hold-00de0ef381c12dc842e0872453d35aa4b49fa488c0427e68b7dd5ac63e151eae9868292a9293010000", + "kind": { + "Write": { + "CLValue": { + "cl_type": "U512", + "bytes": "0500743ba40b", + "parsed": "50000000000" + } + } + } + }, + { + "key": "bid-addr-012f3fb80d362ad0a922f446915a259c9aaec9ba99292b3e50ff2359c458007309", + "kind": "Identity" + }, + { + "key": "bid-addr-042f3fb80d362ad0a922f446915a259c9aaec9ba99292b3e50ff2359c4580073090100000000000000", + "kind": { + "Write": { + "BidKind": { + "Credit": { + "validator_public_key": "01fed662dc7f1f7af43ad785ba07a8cc05b7a96f9ee69613cfde43bc56bec1140b", + "era_id": 1, + "amount": "50000000000" + } + } + } + } + } + ] + } + } + } + } +} diff --git a/tests/key/key_test.go b/tests/key/key_test.go index 34f9968..5f44cc1 100644 --- a/tests/key/key_test.go +++ b/tests/key/key_test.go @@ -23,6 +23,7 @@ func Test_Key_Constructor_fromString(t *testing.T) { {"byte-code prefix", "byte-code-v1-wasm-1b1e23596b8c901a65a13e9d314ca2fff440e69df42f226a76a9bbfbb90df1fa", "byte-code-v1-wasm-1b1e23596b8c901a65a13e9d314ca2fff440e69df42f226a76a9bbfbb90df1fa"}, {"bid-addr- prefix", "bid-addr-01da3cd8cc4c8f34e7731583e67ddc211ff9b5c3f2c52640582415c2cce9315b2a", "bid-addr-01da3cd8cc4c8f34e7731583e67ddc211ff9b5c3f2c52640582415c2cce9315b2a"}, {"bid-addr- prefix", "bid-addr-0494f1805abf61fac1b206d35773f1d1e71be2a162b58acd29fbca6ea5e8e73bedea00000000000000", "bid-addr-0494f1805abf61fac1b206d35773f1d1e71be2a162b58acd29fbca6ea5e8e73bedea00000000000000"}, + {"bid-addr- prefix", "bid-addr-032f3fb80d362ad0a922f446915a259c9aaec9ba99292b3e50ff2359c458007309de0ef381c12dc842e0872453d35aa4b49fa488c0427e68b7dd5ac63e151eae98", "bid-addr-032f3fb80d362ad0a922f446915a259c9aaec9ba99292b3e50ff2359c458007309de0ef381c12dc842e0872453d35aa4b49fa488c0427e68b7dd5ac63e151eae98"}, {"message-topic prefix", "message-topic-entity-contract-55d4a6915291da12afded37fa5bc01f0803a2f0faf6acb7ec4c7ca6ab76f3330-5721a6d9d7a9afe5dfdb35276fb823bed0f825350e4d865a5ec0110c380de4e1", "message-topic-entity-contract-55d4a6915291da12afded37fa5bc01f0803a2f0faf6acb7ec4c7ca6ab76f3330-5721a6d9d7a9afe5dfdb35276fb823bed0f825350e4d865a5ec0110c380de4e1"}, {"message-system prefix", "message-topic-entity-system-55d4a6915291da12afded37fa5bc01f0803a2f0faf6acb7ec4c7ca6ab76f3330-5721a6d9d7a9afe5dfdb35276fb823bed0f825350e4d865a5ec0110c380de4e1", "message-topic-entity-system-55d4a6915291da12afded37fa5bc01f0803a2f0faf6acb7ec4c7ca6ab76f3330-5721a6d9d7a9afe5dfdb35276fb823bed0f825350e4d865a5ec0110c380de4e1"}, {"message-account prefix", "message-topic-entity-account-55d4a6915291da12afded37fa5bc01f0803a2f0faf6acb7ec4c7ca6ab76f3330-5721a6d9d7a9afe5dfdb35276fb823bed0f825350e4d865a5ec0110c380de4e1", "message-topic-entity-account-55d4a6915291da12afded37fa5bc01f0803a2f0faf6acb7ec4c7ca6ab76f3330-5721a6d9d7a9afe5dfdb35276fb823bed0f825350e4d865a5ec0110c380de4e1"}, diff --git a/tests/rpc/rpc_client_test.go b/tests/rpc/rpc_client_test.go index 306d09c..41822c0 100644 --- a/tests/rpc/rpc_client_test.go +++ b/tests/rpc/rpc_client_test.go @@ -117,6 +117,9 @@ func Test_DefaultClient_GetTransaction_Example(t *testing.T) { { filePath: "../data/transaction/get_transaction_native_target.json", }, + { + filePath: "../data/transaction/get_transaction_with_delegator_kind.json", + }, } for _, tt := range tests { t.Run("GetTransaction", func(t *testing.T) { diff --git a/tests/types/era_summary_test.go b/tests/types/era_summary_test.go index e6c6ff8..51ae9ea 100644 --- a/tests/types/era_summary_test.go +++ b/tests/types/era_summary_test.go @@ -14,14 +14,22 @@ func Test_EraSummary_MarshalUnmarshal_ShouldReturnSameResult(t *testing.T) { tests := []struct { name string fixturePath string + isPurse bool }{ { "V1 EraSummary", "../data/era/era_summary_example.json", + false, }, { "V2 EraSummary", "../data/era/era_summary_v2.json", + false, + }, + { + "V2 EraSummary", + "../data/era/era_summary_v2_delegator_kind_purse.json", + true, }, } for _, test := range tests { @@ -35,7 +43,12 @@ func Test_EraSummary_MarshalUnmarshal_ShouldReturnSameResult(t *testing.T) { for _, summary := range era.StoredValue.EraInfo.SeigniorageAllocations { if summary.Delegator != nil { - assert.NotNil(t, summary.Delegator.DelegatorKind.PublicKey) + if !test.isPurse { + assert.NotNil(t, summary.Delegator.DelegatorKind.PublicKey) + } + if test.isPurse { + assert.NotNil(t, summary.Delegator.DelegatorKind.Purse) + } } } }) diff --git a/types/era_info.go b/types/era_info.go index 89faaeb..2110f29 100644 --- a/types/era_info.go +++ b/types/era_info.go @@ -1,6 +1,7 @@ package types import ( + "encoding/hex" "encoding/json" "errors" @@ -84,3 +85,44 @@ type DelegatorKind struct { // Delegation from purse. Purse *key.URef `json:"Purse,omitempty"` } + +func (t *DelegatorKind) UnmarshalJSON(data []byte) error { + if t == nil { + return errors.New("json.RawMessage: UnmarshalJSON on nil pointer") + } + temp := struct { + PublicKey *keypair.PublicKey `json:"PublicKey,omitempty"` + // purse is represented not in format at uref-{uref-bytes}-{access} + // but just a hex bytes + Purse *string `json:"Purse,omitempty"` + }{} + + if err := json.Unmarshal(data, &temp); err != nil { + return err + } + + if temp.PublicKey != nil { + *t = DelegatorKind{ + PublicKey: temp.PublicKey, + } + } else if temp.Purse != nil { + urefBytes, err := hex.DecodeString(*temp.Purse) + if err != nil { + return err + } + + // added one byte for default access + uref, err := key.NewURefFromBytes(append(urefBytes, byte(7))) + if err != nil { + return err + } + + *t = DelegatorKind{ + Purse: &uref, + } + } else { + return errors.New("unexpected DelegatorKind format") + } + + return nil +} diff --git a/types/key/bid_addr.go b/types/key/bid_addr.go index 1a570bd..ced1f73 100644 --- a/types/key/bid_addr.go +++ b/types/key/bid_addr.go @@ -19,19 +19,33 @@ var ( type BidAddrTag uint8 const ( - // Unified BidAddr for legacy unified bid. - Unified BidAddrTag = iota - // Validator BidAddr for validator bid. - Validator - // Delegator BidAddr for delegator bid. - Delegator - // Credit BidAddr for auction credit. - Credit = 4 + UnifiedTag BidAddrTag = iota + ValidatorTag + DelegatedAccountTag + DelegatedPurseTag + CreditTag + ReservedDelegationAccountTag + ReservedDelegationPurseTag + UnbondAccountTag + UnbondPurseTag ) +var allowedBidAddrTags = map[BidAddrTag]struct{}{ + UnifiedTag: {}, + ValidatorTag: {}, + DelegatedAccountTag: {}, + DelegatedPurseTag: {}, + CreditTag: {}, + ReservedDelegationAccountTag: {}, + ReservedDelegationPurseTag: {}, + UnbondAccountTag: {}, + UnbondPurseTag: {}, +} + func NewBidAddrTagFromByte(tag uint8) (BidAddrTag, error) { addrTag := BidAddrTag(tag) - if addrTag != Unified && addrTag != Validator && addrTag != Delegator && addrTag != Credit { + + if _, ok := allowedBidAddrTags[addrTag]; !ok { return 0, ErrInvalidBidAddrTag } @@ -43,85 +57,61 @@ const ( UnifiedOrValidatorAddrLen = 33 // CreditAddrLen BidAddrTag(1) + Hash(32) + EraId(8) CreditAddrLen = 41 - // DelegatorAddrLen BidAddrTag(1) + Hash(32) + Hash(32) - DelegatorAddrLen = 65 + // ValidatorHashDelegatorHashAddrLen BidAddrTag(1) + Hash(32) + Hash(32) + ValidatorHashDelegatorHashAddrLen = 65 + // ValidatorHashDelegatorUrefAddrLen BidAddrTag(1) + Hash(32) + URef(32) + ValidatorHashDelegatorUrefAddrLen = 65 ) // BidAddr Bid Address type BidAddr struct { - Unified *Hash - Validator *Hash - Delegator *struct { + Unified *Hash + Validator *Hash + DelegatedAccount *struct { Validator Hash Delegator Hash } + DelegatedPurse *struct { + Validator Hash + Delegator URef + } Credit *struct { Validator Hash EraId uint64 } -} - -func NewBidAddr(source string) (BidAddr, error) { - hexBytes, err := hex.DecodeString(source) - if err != nil { - return BidAddr{}, err - } - - if len(source) < UnifiedOrValidatorAddrLen { - return BidAddr{}, ErrInvalidBidAddrFormat - } - bitAddrTag, err := NewBidAddrTagFromByte(hexBytes[0]) - if err != nil { - return BidAddr{}, err + ReservedDelegationAccount *struct { + Validator Hash + Delegator Hash } - if len(hexBytes) == UnifiedOrValidatorAddrLen { - hash, err := NewHashFromBytes(hexBytes[1:]) - if err != nil { - return BidAddr{}, err - } - switch bitAddrTag { - case Unified: - return BidAddr{Unified: &hash}, nil - case Validator: - return BidAddr{Validator: &hash}, nil - default: - return BidAddr{}, ErrUnexpectedBidAddrTagInBidAddr - } + ReservedDelegationPurse *struct { + Validator Hash + Delegator URef } - validatorHash, err := NewHashFromBytes(hexBytes[1:34]) - if err != nil { - return BidAddr{}, err + UnbondAccount *struct { + Validator Hash + Delegator Hash } - if len(hexBytes) == CreditAddrLen { - var eraID uint64 - if err := binary.Read(bytes.NewReader(hexBytes[33:]), binary.LittleEndian, &eraID); err != nil { - return BidAddr{}, err - } - - return BidAddr{Credit: &struct { - Validator Hash - EraId uint64 - }{Validator: validatorHash, EraId: eraID}}, nil + UnbondPurse *struct { + Validator Hash + Delegator URef } +} - delegatorHash, err := NewHashFromBytes(hexBytes[33:]) +func NewBidAddr(source string) (BidAddr, error) { + hexBytes, err := hex.DecodeString(source) if err != nil { return BidAddr{}, err } - - return newDelegatorBidAddr(validatorHash, delegatorHash), nil + buf := bytes.NewBuffer(hexBytes) + return NewBidAddrFromBuffer(buf) } func NewBidAddrFromBuffer(buf *bytes.Buffer) (BidAddr, error) { - if buf.Len() < UnifiedOrValidatorAddrLen { - return BidAddr{}, ErrInvalidBidAddrFormat - } - tag, err := buf.ReadByte() if err != nil { return BidAddr{}, err @@ -132,36 +122,85 @@ func NewBidAddrFromBuffer(buf *bytes.Buffer) (BidAddr, error) { return BidAddr{}, err } - if bitAddrTag == Unified { - hash, err := NewByteHashFromBuffer(buf) + switch bitAddrTag { + case UnifiedTag: + hash, err := NewHashFromBytes(buf.Next(ByteHashLen)) if err != nil { return BidAddr{}, err } - return BidAddr{ - Unified: &hash, - }, nil - } - - if bitAddrTag == Validator { - hash, err := NewByteHashFromBuffer(buf) + return BidAddr{Unified: &hash}, nil + case ValidatorTag: + hash, err := NewHashFromBytes(buf.Next(ByteHashLen)) if err != nil { return BidAddr{}, err } - return BidAddr{ - Validator: &hash, - }, nil - } - - validatorHash, err := NewByteHashFromBuffer(buf) - if err != nil { - return BidAddr{}, err - } - - delegatorHash, err := NewByteHashFromBuffer(buf) - if err != nil { - return BidAddr{}, err + return BidAddr{Validator: &hash}, nil + case DelegatedAccountTag: + validator, delegator, err := readValidatorDelegatorHash(buf) + if err != nil { + return BidAddr{}, err + } + return BidAddr{DelegatedAccount: &struct { + Validator Hash + Delegator Hash + }{Validator: validator, Delegator: delegator}}, nil + case DelegatedPurseTag: + validator, delegator, err := readValidatorHashDelegatorUref(buf) + if err != nil { + return BidAddr{}, err + } + return BidAddr{DelegatedPurse: &struct { + Validator Hash + Delegator URef + }{Validator: validator, Delegator: delegator}}, nil + case CreditTag: + validator, eraID, err := readValidatorHashEraID(buf) + if err != nil { + return BidAddr{}, err + } + return BidAddr{Credit: &struct { + Validator Hash + EraId uint64 + }{Validator: validator, EraId: eraID}}, nil + case ReservedDelegationAccountTag: + validator, delegator, err := readValidatorDelegatorHash(buf) + if err != nil { + return BidAddr{}, err + } + return BidAddr{ReservedDelegationAccount: &struct { + Validator Hash + Delegator Hash + }{Validator: validator, Delegator: delegator}}, nil + case ReservedDelegationPurseTag: + validator, delegator, err := readValidatorHashDelegatorUref(buf) + if err != nil { + return BidAddr{}, err + } + return BidAddr{ReservedDelegationPurse: &struct { + Validator Hash + Delegator URef + }{Validator: validator, Delegator: delegator}}, nil + case UnbondAccountTag: + validator, delegator, err := readValidatorDelegatorHash(buf) + if err != nil { + return BidAddr{}, err + } + return BidAddr{UnbondAccount: &struct { + Validator Hash + Delegator Hash + }{Validator: validator, Delegator: delegator}}, nil + case UnbondPurseTag: + validator, delegator, err := readValidatorHashDelegatorUref(buf) + if err != nil { + return BidAddr{}, err + } + return BidAddr{UnbondPurse: &struct { + Validator Hash + Delegator URef + }{Validator: validator, Delegator: delegator}}, nil + default: + return BidAddr{}, ErrUnexpectedBidAddrTagInBidAddr } - return newDelegatorBidAddr(validatorHash, delegatorHash), nil } func (h *BidAddr) UnmarshalJSON(data []byte) error { @@ -190,38 +229,111 @@ func (h BidAddr) Bytes() []byte { switch { case h.Unified != nil: res := make([]byte, 0, UnifiedOrValidatorAddrLen) - res = append(res, byte(Unified)) + res = append(res, byte(UnifiedTag)) return append(res, h.Unified.Bytes()...) case h.Validator != nil: res := make([]byte, 0, UnifiedOrValidatorAddrLen) - res = append(res, byte(Validator)) + res = append(res, byte(ValidatorTag)) return append(res, h.Validator.Bytes()...) - case h.Delegator != nil: - res := make([]byte, 0, DelegatorAddrLen) - res = append(res, byte(Delegator)) - res = append(res, h.Delegator.Validator.Bytes()...) - return append(res, h.Delegator.Delegator.Bytes()...) + case h.DelegatedAccount != nil: + res := make([]byte, 0, ValidatorHashDelegatorHashAddrLen) + res = append(res, byte(DelegatedAccountTag)) + res = append(res, h.DelegatedAccount.Validator.Bytes()...) + return append(res, h.DelegatedAccount.Delegator.Bytes()...) + case h.DelegatedPurse != nil: + res := make([]byte, 0, ValidatorHashDelegatorUrefAddrLen) + res = append(res, byte(DelegatedPurseTag)) + res = append(res, h.DelegatedPurse.Validator.Bytes()...) + return append(res, h.DelegatedPurse.Delegator.DataBytes()...) case h.Credit != nil: res := make([]byte, 0, CreditAddrLen) - res = append(res, byte(Credit)) + res = append(res, byte(CreditTag)) res = append(res, h.Credit.Validator.Bytes()...) data := make([]byte, cltype.Int64ByteSize) binary.LittleEndian.PutUint64(data, h.Credit.EraId) return append(res, data...) + case h.ReservedDelegationAccount != nil: + res := make([]byte, 0, ValidatorHashDelegatorHashAddrLen) + res = append(res, byte(ReservedDelegationAccountTag)) + res = append(res, h.ReservedDelegationAccount.Validator.Bytes()...) + return append(res, h.ReservedDelegationAccount.Delegator.Bytes()...) + case h.ReservedDelegationPurse != nil: + res := make([]byte, 0, ValidatorHashDelegatorUrefAddrLen) + res = append(res, byte(ReservedDelegationPurseTag)) + res = append(res, h.ReservedDelegationPurse.Validator.Bytes()...) + return append(res, h.ReservedDelegationPurse.Delegator.DataBytes()...) + case h.UnbondAccount != nil: + res := make([]byte, 0, ValidatorHashDelegatorHashAddrLen) + res = append(res, byte(UnbondAccountTag)) + res = append(res, h.UnbondAccount.Validator.Bytes()...) + return append(res, h.UnbondAccount.Delegator.Bytes()...) + case h.UnbondPurse != nil: + res := make([]byte, 0, ValidatorHashDelegatorUrefAddrLen) + res = append(res, byte(UnbondPurseTag)) + res = append(res, h.UnbondPurse.Validator.Bytes()...) + return append(res, h.UnbondPurse.Delegator.DataBytes()...) default: panic("Unexpected BidAddr type") } } -func newDelegatorBidAddr(validatorHash, delegatorHash Hash) BidAddr { - delegator := struct { - Validator Hash - Delegator Hash - }{ - Validator: validatorHash, - Delegator: delegatorHash, +func readValidatorDelegatorHash(buf *bytes.Buffer) (Hash, Hash, error) { + if buf.Len() < ByteHashLen { + return Hash{}, Hash{}, ErrInvalidBidAddrFormat + } + + validator := make([]byte, ByteHashLen) + copy(validator[:], buf.Next(ByteHashLen)) + + if buf.Len() < ByteHashLen { + return Hash{}, Hash{}, ErrInvalidBidAddrFormat + } + + delegator := make([]byte, ByteHashLen) + copy(delegator[:], buf.Next(ByteHashLen)) + + return Hash(validator), Hash(delegator), nil +} + +func readValidatorHashDelegatorUref(buf *bytes.Buffer) (Hash, URef, error) { + if buf.Len() < ByteHashLen { + return Hash{}, URef{}, ErrInvalidBidAddrFormat + } + + validator := make([]byte, ByteHashLen) + copy(validator[:], buf.Next(ByteHashLen)) + + if buf.Len() < ByteHashLen { + return Hash{}, URef{}, ErrInvalidBidAddrFormat } - return BidAddr{ - Delegator: &delegator, + + uref := make([]byte, ByteHashLen) + copy(uref[:], buf.Next(ByteHashLen)) + + urefRes, err := NewURefFromBytes(append(uref, byte(07))) + if err != nil { + return Hash{}, URef{}, err + } + + return Hash(validator), urefRes, nil +} + +func readValidatorHashEraID(buf *bytes.Buffer) (Hash, uint64, error) { + if buf.Len() < ByteHashLen { + return Hash{}, 0, ErrInvalidBidAddrFormat } + + validator := make([]byte, ByteHashLen) + copy(validator[:], buf.Next(ByteHashLen)) + + if buf.Len() < 8 { + return Hash{}, 0, ErrInvalidBidAddrFormat + } + + var eraID uint64 + if err := binary.Read(bytes.NewReader(buf.Next(8)), binary.LittleEndian, &eraID); err != nil { + return Hash{}, 0, ErrInvalidBidAddrFormat + } + + return Hash(validator), eraID, nil } diff --git a/types/key/uref.go b/types/key/uref.go index c8f62fe..cf5a05d 100644 --- a/types/key/uref.go +++ b/types/key/uref.go @@ -31,6 +31,10 @@ type URef struct { access UrefAccess } +func (v URef) DataBytes() []byte { + return v.data[:] +} + func (v URef) Bytes() []byte { return append(v.data[:], []byte{v.access}...) }