Skip to content
This repository has been archived by the owner on Jun 6, 2023. It is now read-only.

Commit

Permalink
Upgrade to HAMT and AMT v3.0.0 (#1356)
Browse files Browse the repository at this point in the history
  • Loading branch information
anorth authored Jan 19, 2021
1 parent c3d95c2 commit 845089a
Show file tree
Hide file tree
Showing 27 changed files with 242 additions and 149 deletions.
5 changes: 2 additions & 3 deletions actors/builtin/market/market_actor.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,6 @@ func (a Actor) CronTick(rt Runtime, _ *abi.EmptyValue) *abi.EmptyValue {

pdErr := msm.pendingDeals.Delete(abi.CidKey(dcid))
builtin.RequireNoErr(rt, pdErr, exitcode.ErrIllegalState, "failed to delete pending proposal %v", dcid)

return nil
}

Expand Down Expand Up @@ -642,8 +641,8 @@ func genRandNextEpoch(currEpoch abi.ChainEpoch, deal *DealProposal, rbF func(cry
func deleteDealProposalAndState(dealId abi.DealID, states *DealMetaArray, proposals *DealArray, removeProposal bool,
removeState bool) error {
if removeProposal {
if err := proposals.Delete(uint64(dealId)); err != nil {
return xerrors.Errorf("failed to delete deal proposal: %w", err)
if err := proposals.Delete(dealId); err != nil {
return xerrors.Errorf("failed to delete proposal %d : %w", dealId, err)
}
}

Expand Down
2 changes: 1 addition & 1 deletion actors/builtin/market/market_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func ConstructState(store adt.Store) (*State, error) {
if err != nil {
return nil, xerrors.Errorf("failed to create empty map: %w", err)
}
emptyDealOpsHamtCid, err := MakeEmptySetMultimap(store, builtin.DefaultHamtBitwidth).Root()
emptyDealOpsHamtCid, err := StoreEmptySetMultimap(store, builtin.DefaultHamtBitwidth)
if err != nil {
return nil, xerrors.Errorf("failed to create empty multiset: %w", err)
}
Expand Down
7 changes: 4 additions & 3 deletions actors/builtin/market/market_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ func TestRemoveAllError(t *testing.T) {
rt := builder.Build(t)
store := adt.AsStore(rt)

smm := market.MakeEmptySetMultimap(store, builtin.DefaultHamtBitwidth)
smm, err := market.MakeEmptySetMultimap(store, builtin.DefaultHamtBitwidth)
require.NoError(t, err)

if err := smm.RemoveAll(42); err != nil {
t.Fatalf("expected no error, got: %s", err)
Expand Down Expand Up @@ -94,7 +95,7 @@ func TestMarketActor(t *testing.T) {
emptyStatesArrayCid, err := adt.StoreEmptyArray(store, market.StatesAmtBitwidth)
assert.NoError(t, err)

emptyMultiMap, err := market.MakeEmptySetMultimap(store, builtin.DefaultHamtBitwidth).Root()
emptyMultiMap, err := market.StoreEmptySetMultimap(store, builtin.DefaultHamtBitwidth)
assert.NoError(t, err)

var state market.State
Expand Down Expand Up @@ -3140,7 +3141,7 @@ func (h *marketActorTestHarness) deleteDealProposal(rt *mock.Runtime, dealId abi
rt.GetState(&st)
deals, err := market.AsDealProposalArray(adt.AsStore(rt), st.Proposals)
require.NoError(h.t, err)
require.NoError(h.t, deals.Delete(uint64(dealId)))
require.NoError(h.t, deals.Delete(dealId))
st.Proposals, err = deals.Root()
require.NoError(h.t, err)
rt.ReplaceState(&st)
Expand Down
32 changes: 24 additions & 8 deletions actors/builtin/market/set_multimap.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package market
import (
"reflect"

"github.com/filecoin-project/go-hamt-ipld/v3"
"github.com/filecoin-project/go-state-types/abi"
cid "github.com/ipfs/go-cid"
"github.com/pkg/errors"
Expand Down Expand Up @@ -31,9 +30,21 @@ func AsSetMultimap(s adt.Store, r cid.Cid, outerBitwidth, innerBitwidth int) (*S

// Creates a new map backed by an empty HAMT and flushes it to the store.
// Both inner and outer HAMTs have branching factor 2^bitwidth.
func MakeEmptySetMultimap(s adt.Store, bitwidth int) *SetMultimap {
m := adt.MakeEmptyMap(s, bitwidth)
return &SetMultimap{mp: m, store: s, innerBitwidth: bitwidth}
func MakeEmptySetMultimap(s adt.Store, bitwidth int) (*SetMultimap, error) {
m, err := adt.MakeEmptyMap(s, bitwidth)
if err != nil {
return nil, err
}
return &SetMultimap{mp: m, store: s, innerBitwidth: bitwidth}, nil
}

// Writes a new empty map to the store and returns its CID.
func StoreEmptySetMultimap(s adt.Store, bitwidth int) (cid.Cid, error){
mm, err := MakeEmptySetMultimap(s, bitwidth)
if err != nil {
return cid.Undef, err
}
return mm.Root()
}

// Returns the root cid of the underlying HAMT.
Expand All @@ -49,7 +60,10 @@ func (mm *SetMultimap) Put(epoch abi.ChainEpoch, v abi.DealID) error {
return err
}
if !found {
set = adt.MakeEmptySet(mm.store, mm.innerBitwidth)
set, err = adt.MakeEmptySet(mm.store, mm.innerBitwidth)
if err != nil {
return err
}
}

// Add to the set.
Expand Down Expand Up @@ -78,7 +92,10 @@ func (mm *SetMultimap) PutMany(epoch abi.ChainEpoch, vs []abi.DealID) error {
return err
}
if !found {
set = adt.MakeEmptySet(mm.store, mm.innerBitwidth)
set, err = adt.MakeEmptySet(mm.store, mm.innerBitwidth)
if err != nil {
return err
}
}

// Add to the set.
Expand All @@ -103,8 +120,7 @@ func (mm *SetMultimap) PutMany(epoch abi.ChainEpoch, vs []abi.DealID) error {

// Removes all values for a key.
func (mm *SetMultimap) RemoveAll(key abi.ChainEpoch) error {
err := mm.mp.Delete(abi.UIntKey(uint64(key)))
if err != nil && !xerrors.Is(err, hamt.ErrNotFound) {
if _, err := mm.mp.TryDelete(abi.UIntKey(uint64(key))); err != nil {
return xerrors.Errorf("failed to delete set key %v: %w", key, err)
}
return nil
Expand Down
4 changes: 2 additions & 2 deletions actors/builtin/market/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ func (t *DealArray) Set(k abi.DealID, value *DealProposal) error {
return t.Array.Set(uint64(k), value)
}

func (t *DealArray) Delete(key uint64) error {
return t.Array.Delete(key)
func (t *DealArray) Delete(id abi.DealID) error {
return t.Array.Delete(uint64(id))
}

// A specialization of a array to deals.
Expand Down
4 changes: 2 additions & 2 deletions actors/builtin/miner/bitfield_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (q BitfieldQueue) Cut(toCut bitfield.BitField) error {
}); err != nil {
return xerrors.Errorf("failed to cut from bitfield queue: %w", err)
}
if err := q.BatchDelete(epochsToRemove); err != nil {
if err := q.BatchDelete(epochsToRemove, true); err != nil {
return xerrors.Errorf("failed to remove empty epochs from bitfield queue: %w", err)
}
return nil
Expand Down Expand Up @@ -135,7 +135,7 @@ func (q BitfieldQueue) PopUntil(until abi.ChainEpoch) (values bitfield.BitField,
return bitfield.New(), false, nil
}

if err = q.BatchDelete(poppedKeys); err != nil {
if err = q.BatchDelete(poppedKeys, true); err != nil {
return bitfield.BitField{}, false, err
}
merged, err := bitfield.MultiMerge(poppedValues...)
Expand Down
13 changes: 4 additions & 9 deletions actors/builtin/miner/deadline_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -1141,21 +1141,16 @@ func (dl *Deadline) TakePoStProofs(store adt.Store, idx uint64) (partitions bitf
if err != nil {
return bitfield.New(), nil, xerrors.Errorf("failed to load proofs: %w", err)
}

// Extract and remove the proof from the proofs array, leaving a hole.
// This will not affect concurrent attempts to refute other proofs.
var post WindowedPoSt
found, err := proofArr.Get(idx, &post)
if err != nil {
if found, err := proofArr.Pop(idx, &post); err != nil {
return bitfield.New(), nil, xerrors.Errorf("failed to retrieve proof %d: %w", idx, err)
} else if !found {
return bitfield.New(), nil, xc.ErrIllegalArgument.Wrapf("proof %d not found", idx)
}

// Delete the proof from the proofs array, leaving a hole.
// This will not affect concurrent attempts to refute other proofs.
err = proofArr.Delete(idx)
if err != nil {
return bitfield.New(), nil, xerrors.Errorf("failed to delete proof %d: %w", idx, err)
}

root, err := proofArr.Root()
if err != nil {
return bitfield.New(), nil, xerrors.Errorf("failed to save proofs: %w", err)
Expand Down
6 changes: 3 additions & 3 deletions actors/builtin/miner/expiration_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ func (q ExpirationQueue) RescheduleAllAsFaults(faultExpiration abi.ChainEpoch) e
}

// Trim the rescheduled epochs from the queue.
if err = q.BatchDelete(rescheduledEpochs); err != nil {
if err = q.BatchDelete(rescheduledEpochs, true); err != nil {
return err
}

Expand Down Expand Up @@ -558,7 +558,7 @@ func (q ExpirationQueue) PopUntil(until abi.ChainEpoch) (*ExpirationSet, error)
return nil, err
}

if err := q.Array.BatchDelete(poppedKeys); err != nil {
if err := q.Array.BatchDelete(poppedKeys, true); err != nil {
return nil, err
}

Expand Down Expand Up @@ -660,7 +660,7 @@ func (q ExpirationQueue) traverseMutate(f func(epoch abi.ChainEpoch, es *Expirat
}); err != nil && err != errStop {
return err
}
if err := q.Array.BatchDelete(epochsEmptied); err != nil {
if err := q.Array.BatchDelete(epochsEmptied, true); err != nil {
return err
}
return nil
Expand Down
2 changes: 1 addition & 1 deletion actors/builtin/miner/partition_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ func (p *Partition) PopEarlyTerminations(store adt.Store, maxSectors uint64) (re
}

// Update early terminations
err = earlyTerminatedQ.BatchDelete(processed)
err = earlyTerminatedQ.BatchDelete(processed, true)
if err != nil {
return TerminationResult{}, false, xerrors.Errorf("failed to remove entries from early terminations queue: %w", err)
}
Expand Down
36 changes: 15 additions & 21 deletions actors/builtin/multisig/multisig_actor.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,13 @@ func (a Actor) Cancel(rt runtime.Runtime, params *TxnIDParams) *abi.EmptyValue {
ptx, err := adt.AsMap(adt.AsStore(rt), st.PendingTxns, builtin.DefaultHamtBitwidth)
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load pending txns")

txn, err := getPendingTransaction(ptx, params.ID)
if err != nil {
rt.Abortf(exitcode.ErrNotFound, "failed to get transaction for cancel: %v", err)
var txn Transaction
found, err := ptx.Pop(params.ID, &txn)
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to pop transaction %v for cancel", params.ID)
if !found {
rt.Abortf(exitcode.ErrNotFound, "no such transaction %v to cancel", params.ID)
}

proposer := txn.Approved[0]
if proposer != callerAddr {
rt.Abortf(exitcode.ErrForbidden, "Cannot cancel another signers transaction")
Expand All @@ -286,9 +289,6 @@ func (a Actor) Cancel(rt runtime.Runtime, params *TxnIDParams) *abi.EmptyValue {
rt.Abortf(exitcode.ErrIllegalState, "hash does not match proposal params (ensure requester is an ID address)")
}

err = ptx.Delete(params.ID)
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to delete pending transaction")

st.PendingTxns, err = ptx.Root()
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush pending transactions")
})
Expand Down Expand Up @@ -501,13 +501,12 @@ func (a Actor) approveTransaction(rt runtime.Runtime, txnID TxnID, txn *Transact
}

func getTransaction(rt runtime.Runtime, ptx *adt.Map, txnID TxnID, proposalHash []byte, checkHash bool) *Transaction {
var txn Transaction

// get transaction from the state trie
var err error
txn, err = getPendingTransaction(ptx, txnID)
if err != nil {
rt.Abortf(exitcode.ErrNotFound, "failed to get transaction for approval: %v", err)
var txn Transaction
found, err := ptx.Get(txnID, &txn)
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load transaction %v for approval", txnID)
if !found {
rt.Abortf(exitcode.ErrNotFound, "no such transaction %v for approval", txnID)
}

// confirm the hashes match
Expand Down Expand Up @@ -548,15 +547,10 @@ func executeTransactionIfApproved(rt runtime.Runtime, st State, txnID TxnID, txn
ptx, err := adt.AsMap(adt.AsStore(rt), st.PendingTxns, builtin.DefaultHamtBitwidth)
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load pending transactions")

// Starting at version 6 we first check if the transaction exists before
// deleting. This allows 1 out of n multisig swaps and removes initiated
// by the swapped/removed signer to go through without an illegal state error
txnExists, err := ptx.Has(txnID)
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to check existance of transaction %v for cleanup", txnID)
if txnExists {
if err := ptx.Delete(txnID); err != nil {
rt.Abortf(exitcode.ErrIllegalState, "failed to delete transaction for cleanup: %v", err)
}
// Allow transaction not to be found when deleting.
// This allows 1 out of n multisig swaps and removes initiated by the swapped/removed signer to go through cleanly.
if _, err := ptx.TryDelete(txnID); err != nil {
rt.Abortf(exitcode.ErrIllegalState, "failed to delete transaction for cleanup: %v", err)
}

st.PendingTxns, err = ptx.Root()
Expand Down
13 changes: 0 additions & 13 deletions actors/builtin/multisig/multisig_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
address "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/exitcode"
cid "github.com/ipfs/go-cid"
"golang.org/x/xerrors"

Expand Down Expand Up @@ -144,18 +143,6 @@ func (st *State) assertAvailable(currBalance abi.TokenAmount, amountToSpend abi.
return nil
}

func getPendingTransaction(ptx *adt.Map, txnID TxnID) (Transaction, error) {
var out Transaction
found, err := ptx.Get(txnID, &out)
if err != nil {
return Transaction{}, xerrors.Errorf("failed to read transaction: %w", err)
}
if !found {
return Transaction{}, exitcode.ErrNotFound.Wrapf("failed to find transaction %v", txnID)
}
return out, nil
}

// An adt.Map key that just preserves the underlying string.
type StringKey string

Expand Down
10 changes: 7 additions & 3 deletions actors/builtin/power/power_actor.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,10 +267,11 @@ func (a Actor) SubmitPoRepForBulkVerify(rt Runtime, sealInfo *proof.SealVerifyIn

store := adt.AsStore(rt)
var mmap *adt.Multimap
var err error
if st.ProofValidationBatch == nil {
mmap = adt.MakeEmptyMultimap(store, builtin.DefaultHamtBitwidth, ProofValidationBatchAmtBitwidth)
mmap, err = adt.MakeEmptyMultimap(store, builtin.DefaultHamtBitwidth, ProofValidationBatchAmtBitwidth)
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to create empty proof validation set")
} else {
var err error
mmap, err = adt.AsMultimap(adt.AsStore(rt), *st.ProofValidationBatch, builtin.DefaultHamtBitwidth, ProofValidationBatchAmtBitwidth)
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load proof batch set")
}
Expand Down Expand Up @@ -486,10 +487,13 @@ func (a Actor) processDeferredCronEvents(rt Runtime) {

// Remove miner claim and leave miner frozen
for _, minerAddr := range failedMinerCrons {
err := st.deleteClaim(claims, minerAddr)
found, err := st.deleteClaim(claims, minerAddr)
if err != nil {
rt.Log(rtt.ERROR, "failed to delete claim for miner %s after failing OnDeferredCronEvent: %s", minerAddr, err)
continue
} else if !found {
rt.Log(rtt.ERROR, "can't find claim for miner %s after failing OnDeferredCronEvent: %s", minerAddr, err)
continue
}

// Decrement miner count to keep stats consistent.
Expand Down
14 changes: 8 additions & 6 deletions actors/builtin/power/power_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func ConstructState(store adt.Store) (*State, error) {
if err != nil {
return nil, xerrors.Errorf("failed to create empty map: %w", err)
}
emptyCronQueueMMapCid, err := adt.MakeEmptyMultimap(store, CronQueueHamtBitwidth, CronQueueAmtBitwidth).Root()
emptyCronQueueMMapCid, err := adt.StoreEmptyMultimap(store, CronQueueHamtBitwidth, CronQueueAmtBitwidth)
if err != nil {
return nil, xerrors.Errorf("failed to create empty multimap: %w", err)
}
Expand Down Expand Up @@ -244,23 +244,25 @@ func (st *State) updateStatsForNewMiner(windowPoStProof abi.RegisteredPoStProof)
return nil
}

func (st *State) deleteClaim(claims *adt.Map, miner addr.Address) error {
func (st *State) deleteClaim(claims *adt.Map, miner addr.Address) (bool, error) {
// Note: this flow loads the claim multiple times, unnecessarily.
// We should refactor to use claims.Pop().
oldClaim, ok, err := getClaim(claims, miner)
if err != nil {
return fmt.Errorf("failed to get claim: %w", err)
return false, fmt.Errorf("failed to get claim: %w", err)
}
if !ok {
return nil // no record, we're done
return false, nil // no record, we're done
}

// subtract from stats as if we were simply removing power
err = st.addToClaim(claims, miner, oldClaim.RawBytePower.Neg(), oldClaim.QualityAdjPower.Neg())
if err != nil {
return fmt.Errorf("failed to subtract miner power before deleting claim: %w", err)
return false, fmt.Errorf("failed to subtract miner power before deleting claim: %w", err)
}

// delete claim from state to invalidate miner
return claims.Delete(abi.AddrKey(miner))
return true, claims.Delete(abi.AddrKey(miner))
}

func getClaim(claims *adt.Map, a addr.Address) (*Claim, bool, error) {
Expand Down
3 changes: 2 additions & 1 deletion actors/builtin/verifreg/verified_registry_actor.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,9 @@ func (a Actor) RemoveVerifier(rt runtime.Runtime, verifierAddr *addr.Address) *a
verifiers, err := adt.AsMap(adt.AsStore(rt), st.Verifiers, builtin.DefaultHamtBitwidth)
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load verifiers")

err = verifiers.Delete(abi.AddrKey(verifier))
found, err := verifiers.TryDelete(abi.AddrKey(verifier))
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to remove verifier")
builtin.RequireParam(rt, found, "no such verifier %v", verifierAddr)

st.Verifiers, err = verifiers.Root()
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush verifiers")
Expand Down
2 changes: 1 addition & 1 deletion actors/builtin/verifreg/verified_registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func TestRemoveVerifier(t *testing.T) {
rt.ExpectValidateCallerAddr(ac.rootkey)
rt.SetCaller(ac.rootkey, builtin.VerifiedRegistryActorCodeID)
v := tutil.NewIDAddr(t, 501)
rt.ExpectAbort(exitcode.ErrIllegalState, func() {
rt.ExpectAbort(exitcode.ErrIllegalArgument, func() {
rt.Call(ac.RemoveVerifier, &v)
})
ac.checkState(rt)
Expand Down
Loading

0 comments on commit 845089a

Please sign in to comment.