Skip to content
This repository was archived by the owner on Apr 4, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion chain/activity.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (

type Activity struct {
Tmstmp int64 `serialize:"true" json:"timestamp"`
Sender string `serialize:"true" json:"sender"`
TxID ids.ID `serialize:"true" json:"txId"`
Typ string `serialize:"true" json:"type"`
Sender string `serialize:"true" json:"sender,omitempty"` // empty when reward
Space string `serialize:"true" json:"space,omitempty"`
Key string `serialize:"true" json:"key,omitempty"`
To string `serialize:"true" json:"to,omitempty"` // common.Address will be 0x000 when not populated
Expand Down
4 changes: 4 additions & 0 deletions chain/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type StatelessBlock struct {
t time.Time
bytes []byte

Winners map[ids.ID]*Activity

vm VM
children []*StatelessBlock
onAcceptDB *versiondb.Database
Expand Down Expand Up @@ -90,6 +92,7 @@ func ParseStatefulBlock(
bytes: source,
st: status,
vm: vm,
Winners: map[ids.ID]*Activity{},
}
id, err := ids.ToID(crypto.Keccak256(b.bytes))
if err != nil {
Expand All @@ -106,6 +109,7 @@ func ParseStatefulBlock(
}

func (b *StatelessBlock) init() error {
b.Winners = map[ids.ID]*Activity{}
bytes, err := Marshal(b.StatefulBlock)
if err != nil {
return err
Expand Down
1 change: 1 addition & 0 deletions chain/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func BuildBlock(vm VM, preferred ids.ID) (snowman.Block, error) {
return nil, err
}

b.Winners = map[ids.ID]*Activity{}
b.Txs = []*Transaction{}
units := uint64(0)
for units < g.TargetUnits && mempool.Len() > 0 {
Expand Down
3 changes: 3 additions & 0 deletions chain/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ const (
Delete = "delete"
Move = "move"
Transfer = "transfer"

// Non-user created event
Reward = "reward"
)

type Input struct {
Expand Down
26 changes: 18 additions & 8 deletions chain/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ package chain
import (
"encoding/json"
"fmt"
"time"

"github.com/ava-labs/avalanchego/database"
"github.com/ava-labs/avalanchego/database/versiondb"
"github.com/ava-labs/avalanchego/utils/units"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
Expand Down Expand Up @@ -118,36 +120,44 @@ func (g *Genesis) Verify() error {
return nil
}

func (g *Genesis) Load(db database.KeyValueWriter, airdropData []byte) error {
func (g *Genesis) Load(db database.Database, airdropData []byte) error {
start := time.Now()
defer func() {
log.Debug("loaded genesis allocations", "t", time.Since(start))
}()

vdb := versiondb.New(db)
if len(g.AirdropHash) > 0 {
h := common.BytesToHash(crypto.Keccak256(airdropData)).Hex()
if g.AirdropHash != h {
return fmt.Errorf("expected standard allocation %s but got %s", g.AirdropHash, h)
}

standardAllocation := []*Airdrop{}
if err := json.Unmarshal(airdropData, &standardAllocation); err != nil {
airdrop := []*Airdrop{}
if err := json.Unmarshal(airdropData, &airdrop); err != nil {
return err
}

for _, alloc := range standardAllocation {
if err := SetBalance(db, alloc.Address, g.AirdropUnits); err != nil {
for _, alloc := range airdrop {
if err := SetBalance(vdb, alloc.Address, g.AirdropUnits); err != nil {
return fmt.Errorf("%w: addr=%s, bal=%d", err, alloc.Address, g.AirdropUnits)
}
}
log.Debug(
"applied airdrop allocation",
"hash", h, "addrs", len(standardAllocation), "balance", g.AirdropUnits,
"hash", h, "addrs", len(airdrop), "balance", g.AirdropUnits,
)
}

// Do custom allocation last in case an address shows up in standard
// allocation
for _, alloc := range g.CustomAllocation {
if err := SetBalance(db, alloc.Address, alloc.Balance); err != nil {
if err := SetBalance(vdb, alloc.Address, alloc.Balance); err != nil {
return fmt.Errorf("%w: addr=%s, bal=%d", err, alloc.Address, alloc.Balance)
}
log.Debug("applied custom allocation", "addr", alloc.Address, "balance", alloc.Balance)
}
return nil

// Commit as a batch to improve speed
return vdb.Commit()
}
14 changes: 8 additions & 6 deletions chain/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,9 @@ func ModifyBalance(db database.KeyValueReaderWriter, address common.Address, add
return n, SetBalance(db, address, n)
}

func ApplyReward(db database.Database, blkID ids.ID, txID ids.ID, sender common.Address, reward uint64) error {
func ApplyReward(
db database.Database, blkID ids.ID, txID ids.ID, sender common.Address, reward uint64,
) (common.Address, bool, error) {
seed := [64]byte{}
copy(seed[:], blkID[:])
copy(seed[32:], txID[:])
Expand All @@ -612,26 +614,26 @@ func ApplyReward(db database.Database, blkID ids.ID, txID ids.ID, sender common.

var i SpaceInfo
if _, err := Unmarshal(cursor.Value(), &i); err != nil {
return err
return common.Address{}, false, err
}
space := string(curKey[2:])

// Do not give sender their funds back
if bytes.Equal(i.Owner[:], sender[:]) {
log.Debug("skipping reward: same owner", "space", space, "owner", i.Owner)
return nil
return common.Address{}, false, nil
}

// Distribute reward
if _, err := ModifyBalance(db, i.Owner, true, reward); err != nil {
return err
return common.Address{}, false, err
}

log.Debug("rewarded space owner", "space", space, "owner", i.Owner, "amount", reward)
return nil
return i.Owner, true, nil
}

// No reward applied
log.Debug("skipping reward: no valid space")
return nil
return common.Address{}, false, nil
}
15 changes: 14 additions & 1 deletion chain/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,20 @@ func (t *Transaction) Execute(g *Genesis, db database.Database, blk *StatelessBl
return nil
}
rewardAmount := t.FeeUnits(g) * blk.Price * g.LotteryRewardMultipler / g.LotteryRewardDivisor
return ApplyReward(db, blk.ID(), t.ID(), t.sender, rewardAmount)
recipient, distributed, err := ApplyReward(db, blk.ID(), t.ID(), t.sender, rewardAmount)
if err != nil {
return err
}
if distributed {
blk.Winners[t.ID()] = &Activity{
Tmstmp: blk.Tmstmp,
Typ: Reward,
TxID: t.ID(),
To: recipient.Hex(),
Units: rewardAmount,
}
}
return nil
}

func (t *Transaction) Activity() *Activity {
Expand Down
5 changes: 4 additions & 1 deletion scripts/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,10 @@ EOF

echo "creating VM genesis file"
rm -f /tmp/spacesvm.genesis
/tmp/spaces-cli genesis 1 /tmp/allocations.json --genesis-file /tmp/spacesvm.genesis
/tmp/spaces-cli genesis 1 /tmp/allocations.json \
--genesis-file /tmp/spacesvm.genesis \
--airdrop-hash 0xccbf8e430b30d08b5b3342208781c40b373d1b5885c1903828f367230a2568da \
--airdrop-units 10000

echo "building runner"
pushd ./tests/runner
Expand Down
10 changes: 10 additions & 0 deletions tests/integration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,16 @@ var _ = ginkgo.Describe("[ClaimTx]", func() {
}
gomega.Ω(found).To(gomega.BeTrue())
})

ginkgo.By("ensure all activity accounted for", func() {
activity, err := instances[0].cli.RecentActivity()
gomega.Ω(err).To(gomega.BeNil())

a0 := activity[0]
gomega.Ω(a0.Typ).To(gomega.Equal("reward"))
gomega.Ω(a0.To).To(gomega.Equal(sender.Hex()))
gomega.Ω(len(a0.Sender)).To(gomega.Equal(0))
})
})

ginkgo.It("fail Gossip ClaimTx to a stale node when missing previous blocks", func() {
Expand Down
4 changes: 4 additions & 0 deletions vm/chain_vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ func (vm *VM) Accepted(b *chain.StatelessBlock) {
activity.Tmstmp = b.Tmstmp
vm.activityCache[vm.activityCacheCursor%cs] = activity
vm.activityCacheCursor++
if reward, ok := b.Winners[tx.ID()]; ok {
vm.activityCache[vm.activityCacheCursor%cs] = reward
vm.activityCacheCursor++
}
}
}

Expand Down