diff --git a/alphabet/alphabet_contract.go b/alphabet/alphabet_contract.go index f1a8971..f80c541 100644 --- a/alphabet/alphabet_contract.go +++ b/alphabet/alphabet_contract.go @@ -2,9 +2,7 @@ package alphabetcontract import ( "github.com/nspcc-dev/neo-go/pkg/interop" - "github.com/nspcc-dev/neo-go/pkg/interop/binary" "github.com/nspcc-dev/neo-go/pkg/interop/contract" - "github.com/nspcc-dev/neo-go/pkg/interop/crypto" "github.com/nspcc-dev/neo-go/pkg/interop/native/gas" "github.com/nspcc-dev/neo-go/pkg/interop/native/management" "github.com/nspcc-dev/neo-go/pkg/interop/native/neo" @@ -15,10 +13,13 @@ import ( const ( netmapKey = "netmapScriptHash" - indexKey = "index" - totalKey = "threshold" - nameKey = "name" - voteKey = "ballots" + proxyKey = "proxyScriptHash" + + indexKey = "index" + totalKey = "threshold" + nameKey = "name" + + version = 1 ) var ctx storage.Context @@ -35,23 +36,22 @@ func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) { } } -func Init(owner interop.Hash160, addrNetmap []byte, name string, index, total int) { +func Init(owner interop.Hash160, addrNetmap, addrProxy interop.Hash160, name string, index, total int) { if !common.HasUpdateAccess(ctx) { panic("only owner can reinitialize contract") } - if len(addrNetmap) != 20 { + if len(addrNetmap) != 20 || len(addrProxy) != 20 { panic("incorrect length of contract script hash") } storage.Put(ctx, common.OwnerKey, owner) storage.Put(ctx, netmapKey, addrNetmap) + storage.Put(ctx, proxyKey, addrProxy) storage.Put(ctx, nameKey, name) storage.Put(ctx, indexKey, index) storage.Put(ctx, totalKey, total) - common.SetSerialized(ctx, voteKey, []common.Ballot{}) - runtime.Log(name + " contract initialized") } @@ -115,35 +115,40 @@ func Emit() bool { contractHash := runtime.GetExecutingScriptHash() - _ = neo.Transfer(contractHash, contractHash, neo.BalanceOf(contractHash), nil) + neo.Transfer(contractHash, contractHash, neo.BalanceOf(contractHash), nil) gasBalance := gas.BalanceOf(contractHash) - gasPerNode := gasBalance * 7 / 8 / len(innerRingKeys) + proxyAddr := storage.Get(ctx, proxyKey).(interop.Hash160) - if gasPerNode == 0 { + proxyGas := gasBalance / 2 + if proxyGas == 0 { runtime.Log("no gas to emit") return false } - for i := range innerRingKeys { - node := innerRingKeys[i] - address := contract.CreateStandardAccount(node.PublicKey) + gas.Transfer(contractHash, proxyAddr, proxyGas, nil) + runtime.Log("utility token has been emitted to proxy contract") - _ = gas.Transfer(contractHash, address, gasPerNode, nil) + gasPerNode := gasBalance / 2 * 7 / 8 / len(innerRingKeys) + + if gasPerNode != 0 { + for _, node := range innerRingKeys { + address := contract.CreateStandardAccount(node.PublicKey) + gas.Transfer(contractHash, address, gasPerNode, nil) + } + + runtime.Log("utility token has been emitted to inner ring nodes") } - runtime.Log("utility token has been emitted to inner ring nodes") return true } func Vote(epoch int, candidates [][]byte) { - innerRingKeys := irList() - threshold := total()/3*2 + 1 index := index() name := name() - key := common.InnerRingInvoker(innerRingKeys) - if len(key) == 0 { + multiaddr := common.InnerRingMultiAddressViaStorage(ctx, netmapKey) + if !runtime.CheckWitness(multiaddr) { panic("invalid invoker") } @@ -152,22 +157,14 @@ func Vote(epoch int, candidates [][]byte) { panic("invalid epoch") } - id := voteID(epoch, candidates) - n := vote(ctx, curEpoch, id, key) + candidate := candidates[index%len(candidates)] + address := runtime.GetExecutingScriptHash() - if n >= threshold { - candidate := candidates[index%len(candidates)] - address := runtime.GetExecutingScriptHash() - - ok := neo.Vote(address, candidate) - if ok { - runtime.Log(name + ": successfully voted for validator") - removeVotes(ctx, id) - } else { - runtime.Log(name + ": vote has been failed") - } + ok := neo.Vote(address, candidate) + if ok { + runtime.Log(name + ": successfully voted for validator") } else { - runtime.Log(name + ": saved vote for validator") + runtime.Log(name + ": vote has been failed") } return @@ -177,85 +174,6 @@ func Name() string { return name() } -func vote(ctx storage.Context, epoch int, id, from []byte) int { - var ( - newCandidates []common.Ballot - candidates = getBallots(ctx) - found = -1 - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if common.BytesEqual(cnd.ID, id) { - voters := cnd.Voters - - for j := range voters { - if common.BytesEqual(voters[j], from) { - return len(voters) - } - } - - voters = append(voters, from) - cnd = common.Ballot{ID: id, Voters: voters, Height: epoch} - found = len(voters) - } - - // add only valid ballots with current epochs - if cnd.Height == epoch { - newCandidates = append(newCandidates, cnd) - } - } - - if found < 0 { - voters := [][]byte{from} - newCandidates = append(newCandidates, common.Ballot{ - ID: id, - Voters: voters, - Height: epoch}) - found = 1 - } - - common.SetSerialized(ctx, voteKey, newCandidates) - - return found -} - -func removeVotes(ctx storage.Context, id []byte) { - var ( - newCandidates []common.Ballot - candidates = getBallots(ctx) - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if !common.BytesEqual(cnd.ID, id) { - newCandidates = append(newCandidates, cnd) - } - } - - common.SetSerialized(ctx, voteKey, newCandidates) -} - -func getBallots(ctx storage.Context) []common.Ballot { - data := storage.Get(ctx, voteKey) - if data != nil { - return binary.Deserialize(data.([]byte)).([]common.Ballot) - } - - return []common.Ballot{} -} - -func voteID(epoch interface{}, args [][]byte) []byte { - var ( - result []byte - epochBytes = epoch.([]byte) - ) - - result = append(result, epochBytes...) - - for i := range args { - result = append(result, args[i]...) - } - - return crypto.SHA256(result) +func Version() int { + return version }