From 1dcfb59a1f013c894c44b14c1f05eb1f0213231e Mon Sep 17 00:00:00 2001 From: Alex Vanin Date: Tue, 15 Dec 2020 15:19:13 +0300 Subject: [PATCH] [#23] alphabet: Use single contract instead of template Signed-off-by: Alex Vanin --- Makefile | 6 +- alphabet/alphabet.go | 54 ---- alphabet/alphabet.tpl | 287 ------------------ ...dobro_contract.go => alphabet_contract.go} | 48 ++- alphabet/az/az_contract.go | 287 ------------------ alphabet/buky/buky_contract.go | 287 ------------------ alphabet/glagoli/glagoli_contract.go | 287 ------------------ alphabet/jest/jest_contract.go | 287 ------------------ alphabet/vedi/vedi_contract.go | 287 ------------------ alphabet/zhivete/zhivete_contract.go | 287 ------------------ 10 files changed, 36 insertions(+), 2081 deletions(-) delete mode 100644 alphabet/alphabet.go delete mode 100644 alphabet/alphabet.tpl rename alphabet/{dobro/dobro_contract.go => alphabet_contract.go} (87%) delete mode 100644 alphabet/az/az_contract.go delete mode 100644 alphabet/buky/buky_contract.go delete mode 100644 alphabet/glagoli/glagoli_contract.go delete mode 100644 alphabet/jest/jest_contract.go delete mode 100644 alphabet/vedi/vedi_contract.go delete mode 100644 alphabet/zhivete/zhivete_contract.go diff --git a/Makefile b/Makefile index 1bce766..aec885e 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ build: all all: sidechain mainnet sidechain: alphabet morph -alphabet_sc = az buky vedi glagoli dobro jest zhivete +alphabet_sc = alphabet morph_sc = audit balance container neofsid netmap reputation mainnet_sc = neofs @@ -21,11 +21,11 @@ $(if $(2),$(2)$(1)/$(1)_contract.go: alphabet/alphabet.go alphabet/alphabet.tpl ) endef -$(foreach sc,$(alphabet_sc),$(eval $(call sc_template,$(sc),alphabet/))) +$(foreach sc,$(alphabet_sc),$(eval $(call sc_template,$(sc)))) $(foreach sc,$(morph_sc),$(eval $(call sc_template,$(sc)))) $(foreach sc,$(mainnet_sc),$(eval $(call sc_template,$(sc)))) -alphabet: $(foreach sc,$(alphabet_sc),alphabet/$(sc)/$(sc)_contract.nef) +alphabet: $(foreach sc,$(alphabet_sc),$(sc)/$(sc)_contract.nef) morph: $(foreach sc,$(morph_sc),$(sc)/$(sc)_contract.nef) mainnet: $(foreach sc,$(mainnet_sc),$(sc)/$(sc)_contract.nef) diff --git a/alphabet/alphabet.go b/alphabet/alphabet.go deleted file mode 100644 index 606003d..0000000 --- a/alphabet/alphabet.go +++ /dev/null @@ -1,54 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "os" - "path" - "strings" - "text/template" -) - -const ( - root = "alphabet" - templateName = "alphabet.tpl" -) - -func main() { - glagolic := []string{ - "Az", "Buky", "Vedi", "Glagoli", "Dobro", "Jest", "Zhivete", - } - - data, err := ioutil.ReadFile(path.Join(root, templateName)) - die("can't read template file", err) - - tmpl := template.Must(template.New("").Parse(string(data))) - - for index, name := range glagolic { - lowercaseName := strings.ToLower(name) - - if _, err := os.Stat(path.Join(root, lowercaseName)); os.IsNotExist(err) { - os.Mkdir(path.Join(root, lowercaseName), 0755) - } - - dst, err := os.Create(path.Join(root, lowercaseName, lowercaseName+"_contract.go")) - die("can't create file", err) - - err = tmpl.Execute(dst, map[string]interface{}{ - "Name": name, - "Index": index, - }) - die("can't generate code from template", err) - - die("can't close generated file", dst.Close()) - } - - os.Exit(0) -} - -func die(msg string, err error) { - if err != nil { - fmt.Printf(msg+": %v\n", err) - os.Exit(1) - } -} diff --git a/alphabet/alphabet.tpl b/alphabet/alphabet.tpl deleted file mode 100644 index e3e98be..0000000 --- a/alphabet/alphabet.tpl +++ /dev/null @@ -1,287 +0,0 @@ -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/runtime" - "github.com/nspcc-dev/neo-go/pkg/interop/storage" - "github.com/nspcc-dev/neo-go/pkg/interop/util" -) - -type ( - irNode struct { - key []byte - } - - ballot struct { - id []byte // hash of validators list - n [][]byte // already voted inner ring nodes - height int // height is an neofs epoch when ballot was registered - } -) - -const ( - // native gas token script hash - gasHash = "\x20\x2a\x2d\xd3\xf6\xa6\xe8\xf4\xd3\xb5\xaf\x26\xa7\xfe\xde\xba\x4b\x80\xdf\xb5" - - // native neo token script hash - neoHash = "\xb9\x7b\x8d\x5a\x73\x11\x81\x6f\xf7\xb1\xbf\xb0\x14\x20\xe2\x59\x0d\xa3\xc1\x24" - - name = "{{ .Name }}" - index = {{ .Index }} - - netmapContractKey = "netmapScriptHash" - - threshold = totalAlphabetContracts * 2 / 3 + 1 - voteKey = "ballots" - - totalAlphabetContracts = 7 -) - -var ( - ctx storage.Context -) - -func init() { - if runtime.GetTrigger() != runtime.Application { - panic("contract has not been called in application node") - } - - ctx = storage.GetContext() -} - -// OnPayment is a callback for NEP-17 compatible native GAS and NEO contracts. -func OnPayment(from interop.Hash160, amount int, data interface{}) { - caller := runtime.GetCallingScriptHash() - if !bytesEqual(caller, []byte(gasHash)) && !bytesEqual(caller, []byte(neoHash)) { - panic("onPayment: alphabet contract accepts GAS and NEO only") - } -} - -func Init(addrNetmap []byte) { - if storage.Get(ctx, netmapContractKey) != nil { - panic("contract already deployed") - } - - if len(addrNetmap) != 20 { - panic("incorrect length of contract script hash") - } - - storage.Put(ctx, netmapContractKey, addrNetmap) - - setSerialized(ctx, voteKey, []ballot{}) - - runtime.Log(name + " contract initialized") -} - -func Gas() int { - contractHash := runtime.GetExecutingScriptHash() - return balance(gasHash, contractHash) -} - -func Neo() int { - contractHash := runtime.GetExecutingScriptHash() - return balance(neoHash, contractHash) -} - -func balance(hash string, addr []byte) int { - balance := contract.Call([]byte(hash), "balanceOf", addr) - return balance.(int) -} - -func irList() []irNode { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) - return contract.Call(netmapContractAddr, "innerRingList").([]irNode) -} - -func currentEpoch() int { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) - return contract.Call(netmapContractAddr, "epoch").(int) -} - -func checkPermission(ir []irNode) bool { - if len(ir) <= index { - return false - } - - node := ir[index] - return runtime.CheckWitness(node.key) -} - -func innerRingInvoker(ir []irNode) []byte { - for i := 0; i < len(ir); i++ { - if i >= totalAlphabetContracts { - return nil - } - - node := ir[i] - if runtime.CheckWitness(node.key) { - return node.key - } - } - - return nil -} - -func Emit() bool { - innerRingKeys := irList() - if !checkPermission(innerRingKeys) { - panic("invalid invoker") - } - - contractHash := runtime.GetExecutingScriptHash() - neo := balance(neoHash, contractHash) - - _ = contract.Call([]byte(neoHash), "transfer", contractHash, contractHash, neo, nil) - - gas := balance(gasHash, contractHash) - gasPerNode := gas * 7 / 8 / len(innerRingKeys) - - if gasPerNode == 0 { - runtime.Log("no gas to emit") - return false - } - - for i := range innerRingKeys { - node := innerRingKeys[i] - address := contract.CreateStandardAccount(node.key) - - _ = contract.Call([]byte(gasHash), "transfer", contractHash, address, gasPerNode, nil) - } - - runtime.Log("utility token has been emitted to inner ring nodes") - return true -} - -func Vote(epoch int, candidates [][]byte) { - innerRingKeys := irList() - - key := innerRingInvoker(innerRingKeys) - if len(key) == 0 { - panic("invalid invoker") - } - - curEpoch := currentEpoch() - if epoch != curEpoch { - panic("invalid epoch") - } - - id := voteID(epoch, candidates) - n := vote(ctx, curEpoch, id, key) - - if n >= threshold { - candidate := candidates[index%len(candidates)] - address := runtime.GetExecutingScriptHash() - - ok := contract.Call([]byte(neoHash), "vote", address, candidate).(bool) - if ok { - runtime.Log(name + ": successfully voted for validator") - removeVotes(ctx, id) - } else { - runtime.Log(name + ": vote has been failed") - } - } else { - runtime.Log(name + ": saved vote for validator") - } - - return -} - -func Name() string { - return name -} - -func vote(ctx storage.Context, epoch int, id, from []byte) int { - var ( - newCandidates []ballot - candidates = getBallots(ctx) - found = -1 - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if bytesEqual(cnd.id, id) { - voters := cnd.n - - for j := range voters { - if bytesEqual(voters[j], from) { - return len(voters) - } - } - - voters = append(voters, from) - cnd = ballot{id: id, n: 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, ballot{ - id: id, - n: voters, - height: epoch}) - found = 1 - } - - setSerialized(ctx, voteKey, newCandidates) - - return found -} - -func removeVotes(ctx storage.Context, id []byte) { - var ( - newCandidates []ballot - candidates = getBallots(ctx) - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if !bytesEqual(cnd.id, id) { - newCandidates = append(newCandidates, cnd) - } - } - - setSerialized(ctx, voteKey, newCandidates) -} - -func getBallots(ctx storage.Context) []ballot { - data := storage.Get(ctx, voteKey) - if data != nil { - return binary.Deserialize(data.([]byte)).([]ballot) - } - - return []ballot{} -} - -func setSerialized(ctx storage.Context, key interface{}, value interface{}) { - data := binary.Serialize(value) - storage.Put(ctx, key, data) -} - -// neo-go#1176 -func bytesEqual(a []byte, b []byte) bool { - return util.Equals(string(a), string(b)) -} - -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) -} diff --git a/alphabet/dobro/dobro_contract.go b/alphabet/alphabet_contract.go similarity index 87% rename from alphabet/dobro/dobro_contract.go rename to alphabet/alphabet_contract.go index fc45752..f8bc01c 100644 --- a/alphabet/dobro/dobro_contract.go +++ b/alphabet/alphabet_contract.go @@ -29,15 +29,11 @@ const ( // native neo token script hash neoHash = "\xb9\x7b\x8d\x5a\x73\x11\x81\x6f\xf7\xb1\xbf\xb0\x14\x20\xe2\x59\x0d\xa3\xc1\x24" - name = "Dobro" - index = 4 - - netmapContractKey = "netmapScriptHash" - - threshold = totalAlphabetContracts*2/3 + 1 + netmapKey = "netmapScriptHash" + indexKey = "index" + totalKey = "threshold" + nameKey = "name" voteKey = "ballots" - - totalAlphabetContracts = 7 ) var ( @@ -60,8 +56,8 @@ func OnPayment(from interop.Hash160, amount int, data interface{}) { } } -func Init(addrNetmap []byte) { - if storage.Get(ctx, netmapContractKey) != nil { +func Init(addrNetmap []byte, name string, index, total int) { + if storage.Get(ctx, netmapKey) != nil { panic("contract already deployed") } @@ -69,7 +65,10 @@ func Init(addrNetmap []byte) { panic("incorrect length of contract script hash") } - storage.Put(ctx, netmapContractKey, addrNetmap) + storage.Put(ctx, netmapKey, addrNetmap) + storage.Put(ctx, nameKey, name) + storage.Put(ctx, indexKey, index) + storage.Put(ctx, totalKey, total) setSerialized(ctx, voteKey, []ballot{}) @@ -92,16 +91,30 @@ func balance(hash string, addr []byte) int { } func irList() []irNode { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) + netmapContractAddr := storage.Get(ctx, netmapKey).([]byte) return contract.Call(netmapContractAddr, "innerRingList").([]irNode) } func currentEpoch() int { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) + netmapContractAddr := storage.Get(ctx, netmapKey).([]byte) return contract.Call(netmapContractAddr, "epoch").(int) } +func name() string { + return storage.Get(ctx, nameKey).(string) +} + +func index() int { + return storage.Get(ctx, indexKey).(int) +} + +func total() int { + return storage.Get(ctx, totalKey).(int) +} + func checkPermission(ir []irNode) bool { + index := index() // read from contract memory + if len(ir) <= index { return false } @@ -111,8 +124,10 @@ func checkPermission(ir []irNode) bool { } func innerRingInvoker(ir []irNode) []byte { + amountOfContracts := total() // read from contract memory + for i := 0; i < len(ir); i++ { - if i >= totalAlphabetContracts { + if i >= amountOfContracts { return nil } @@ -157,6 +172,9 @@ func Emit() bool { func Vote(epoch int, candidates [][]byte) { innerRingKeys := irList() + threshold := total()/3*2 + 1 + index := index() + name := name() key := innerRingInvoker(innerRingKeys) if len(key) == 0 { @@ -190,7 +208,7 @@ func Vote(epoch int, candidates [][]byte) { } func Name() string { - return name + return name() } func vote(ctx storage.Context, epoch int, id, from []byte) int { diff --git a/alphabet/az/az_contract.go b/alphabet/az/az_contract.go deleted file mode 100644 index 360dc50..0000000 --- a/alphabet/az/az_contract.go +++ /dev/null @@ -1,287 +0,0 @@ -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/runtime" - "github.com/nspcc-dev/neo-go/pkg/interop/storage" - "github.com/nspcc-dev/neo-go/pkg/interop/util" -) - -type ( - irNode struct { - key []byte - } - - ballot struct { - id []byte // hash of validators list - n [][]byte // already voted inner ring nodes - height int // height is an neofs epoch when ballot was registered - } -) - -const ( - // native gas token script hash - gasHash = "\x20\x2a\x2d\xd3\xf6\xa6\xe8\xf4\xd3\xb5\xaf\x26\xa7\xfe\xde\xba\x4b\x80\xdf\xb5" - - // native neo token script hash - neoHash = "\xb9\x7b\x8d\x5a\x73\x11\x81\x6f\xf7\xb1\xbf\xb0\x14\x20\xe2\x59\x0d\xa3\xc1\x24" - - name = "Az" - index = 0 - - netmapContractKey = "netmapScriptHash" - - threshold = totalAlphabetContracts*2/3 + 1 - voteKey = "ballots" - - totalAlphabetContracts = 7 -) - -var ( - ctx storage.Context -) - -func init() { - if runtime.GetTrigger() != runtime.Application { - panic("contract has not been called in application node") - } - - ctx = storage.GetContext() -} - -// OnPayment is a callback for NEP-17 compatible native GAS and NEO contracts. -func OnPayment(from interop.Hash160, amount int, data interface{}) { - caller := runtime.GetCallingScriptHash() - if !bytesEqual(caller, []byte(gasHash)) && !bytesEqual(caller, []byte(neoHash)) { - panic("onPayment: alphabet contract accepts GAS and NEO only") - } -} - -func Init(addrNetmap []byte) { - if storage.Get(ctx, netmapContractKey) != nil { - panic("contract already deployed") - } - - if len(addrNetmap) != 20 { - panic("incorrect length of contract script hash") - } - - storage.Put(ctx, netmapContractKey, addrNetmap) - - setSerialized(ctx, voteKey, []ballot{}) - - runtime.Log(name + " contract initialized") -} - -func Gas() int { - contractHash := runtime.GetExecutingScriptHash() - return balance(gasHash, contractHash) -} - -func Neo() int { - contractHash := runtime.GetExecutingScriptHash() - return balance(neoHash, contractHash) -} - -func balance(hash string, addr []byte) int { - balance := contract.Call([]byte(hash), "balanceOf", addr) - return balance.(int) -} - -func irList() []irNode { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) - return contract.Call(netmapContractAddr, "innerRingList").([]irNode) -} - -func currentEpoch() int { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) - return contract.Call(netmapContractAddr, "epoch").(int) -} - -func checkPermission(ir []irNode) bool { - if len(ir) <= index { - return false - } - - node := ir[index] - return runtime.CheckWitness(node.key) -} - -func innerRingInvoker(ir []irNode) []byte { - for i := 0; i < len(ir); i++ { - if i >= totalAlphabetContracts { - return nil - } - - node := ir[i] - if runtime.CheckWitness(node.key) { - return node.key - } - } - - return nil -} - -func Emit() bool { - innerRingKeys := irList() - if !checkPermission(innerRingKeys) { - panic("invalid invoker") - } - - contractHash := runtime.GetExecutingScriptHash() - neo := balance(neoHash, contractHash) - - _ = contract.Call([]byte(neoHash), "transfer", contractHash, contractHash, neo, nil) - - gas := balance(gasHash, contractHash) - gasPerNode := gas * 7 / 8 / len(innerRingKeys) - - if gasPerNode == 0 { - runtime.Log("no gas to emit") - return false - } - - for i := range innerRingKeys { - node := innerRingKeys[i] - address := contract.CreateStandardAccount(node.key) - - _ = contract.Call([]byte(gasHash), "transfer", contractHash, address, gasPerNode, nil) - } - - runtime.Log("utility token has been emitted to inner ring nodes") - return true -} - -func Vote(epoch int, candidates [][]byte) { - innerRingKeys := irList() - - key := innerRingInvoker(innerRingKeys) - if len(key) == 0 { - panic("invalid invoker") - } - - curEpoch := currentEpoch() - if epoch != curEpoch { - panic("invalid epoch") - } - - id := voteID(epoch, candidates) - n := vote(ctx, curEpoch, id, key) - - if n >= threshold { - candidate := candidates[index%len(candidates)] - address := runtime.GetExecutingScriptHash() - - ok := contract.Call([]byte(neoHash), "vote", address, candidate).(bool) - if ok { - runtime.Log(name + ": successfully voted for validator") - removeVotes(ctx, id) - } else { - runtime.Log(name + ": vote has been failed") - } - } else { - runtime.Log(name + ": saved vote for validator") - } - - return -} - -func Name() string { - return name -} - -func vote(ctx storage.Context, epoch int, id, from []byte) int { - var ( - newCandidates []ballot - candidates = getBallots(ctx) - found = -1 - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if bytesEqual(cnd.id, id) { - voters := cnd.n - - for j := range voters { - if bytesEqual(voters[j], from) { - return len(voters) - } - } - - voters = append(voters, from) - cnd = ballot{id: id, n: 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, ballot{ - id: id, - n: voters, - height: epoch}) - found = 1 - } - - setSerialized(ctx, voteKey, newCandidates) - - return found -} - -func removeVotes(ctx storage.Context, id []byte) { - var ( - newCandidates []ballot - candidates = getBallots(ctx) - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if !bytesEqual(cnd.id, id) { - newCandidates = append(newCandidates, cnd) - } - } - - setSerialized(ctx, voteKey, newCandidates) -} - -func getBallots(ctx storage.Context) []ballot { - data := storage.Get(ctx, voteKey) - if data != nil { - return binary.Deserialize(data.([]byte)).([]ballot) - } - - return []ballot{} -} - -func setSerialized(ctx storage.Context, key interface{}, value interface{}) { - data := binary.Serialize(value) - storage.Put(ctx, key, data) -} - -// neo-go#1176 -func bytesEqual(a []byte, b []byte) bool { - return util.Equals(string(a), string(b)) -} - -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) -} diff --git a/alphabet/buky/buky_contract.go b/alphabet/buky/buky_contract.go deleted file mode 100644 index e812cc0..0000000 --- a/alphabet/buky/buky_contract.go +++ /dev/null @@ -1,287 +0,0 @@ -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/runtime" - "github.com/nspcc-dev/neo-go/pkg/interop/storage" - "github.com/nspcc-dev/neo-go/pkg/interop/util" -) - -type ( - irNode struct { - key []byte - } - - ballot struct { - id []byte // hash of validators list - n [][]byte // already voted inner ring nodes - height int // height is an neofs epoch when ballot was registered - } -) - -const ( - // native gas token script hash - gasHash = "\x20\x2a\x2d\xd3\xf6\xa6\xe8\xf4\xd3\xb5\xaf\x26\xa7\xfe\xde\xba\x4b\x80\xdf\xb5" - - // native neo token script hash - neoHash = "\xb9\x7b\x8d\x5a\x73\x11\x81\x6f\xf7\xb1\xbf\xb0\x14\x20\xe2\x59\x0d\xa3\xc1\x24" - - name = "Buky" - index = 1 - - netmapContractKey = "netmapScriptHash" - - threshold = totalAlphabetContracts*2/3 + 1 - voteKey = "ballots" - - totalAlphabetContracts = 7 -) - -var ( - ctx storage.Context -) - -func init() { - if runtime.GetTrigger() != runtime.Application { - panic("contract has not been called in application node") - } - - ctx = storage.GetContext() -} - -// OnPayment is a callback for NEP-17 compatible native GAS and NEO contracts. -func OnPayment(from interop.Hash160, amount int, data interface{}) { - caller := runtime.GetCallingScriptHash() - if !bytesEqual(caller, []byte(gasHash)) && !bytesEqual(caller, []byte(neoHash)) { - panic("onPayment: alphabet contract accepts GAS and NEO only") - } -} - -func Init(addrNetmap []byte) { - if storage.Get(ctx, netmapContractKey) != nil { - panic("contract already deployed") - } - - if len(addrNetmap) != 20 { - panic("incorrect length of contract script hash") - } - - storage.Put(ctx, netmapContractKey, addrNetmap) - - setSerialized(ctx, voteKey, []ballot{}) - - runtime.Log(name + " contract initialized") -} - -func Gas() int { - contractHash := runtime.GetExecutingScriptHash() - return balance(gasHash, contractHash) -} - -func Neo() int { - contractHash := runtime.GetExecutingScriptHash() - return balance(neoHash, contractHash) -} - -func balance(hash string, addr []byte) int { - balance := contract.Call([]byte(hash), "balanceOf", addr) - return balance.(int) -} - -func irList() []irNode { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) - return contract.Call(netmapContractAddr, "innerRingList").([]irNode) -} - -func currentEpoch() int { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) - return contract.Call(netmapContractAddr, "epoch").(int) -} - -func checkPermission(ir []irNode) bool { - if len(ir) <= index { - return false - } - - node := ir[index] - return runtime.CheckWitness(node.key) -} - -func innerRingInvoker(ir []irNode) []byte { - for i := 0; i < len(ir); i++ { - if i >= totalAlphabetContracts { - return nil - } - - node := ir[i] - if runtime.CheckWitness(node.key) { - return node.key - } - } - - return nil -} - -func Emit() bool { - innerRingKeys := irList() - if !checkPermission(innerRingKeys) { - panic("invalid invoker") - } - - contractHash := runtime.GetExecutingScriptHash() - neo := balance(neoHash, contractHash) - - _ = contract.Call([]byte(neoHash), "transfer", contractHash, contractHash, neo, nil) - - gas := balance(gasHash, contractHash) - gasPerNode := gas * 7 / 8 / len(innerRingKeys) - - if gasPerNode == 0 { - runtime.Log("no gas to emit") - return false - } - - for i := range innerRingKeys { - node := innerRingKeys[i] - address := contract.CreateStandardAccount(node.key) - - _ = contract.Call([]byte(gasHash), "transfer", contractHash, address, gasPerNode, nil) - } - - runtime.Log("utility token has been emitted to inner ring nodes") - return true -} - -func Vote(epoch int, candidates [][]byte) { - innerRingKeys := irList() - - key := innerRingInvoker(innerRingKeys) - if len(key) == 0 { - panic("invalid invoker") - } - - curEpoch := currentEpoch() - if epoch != curEpoch { - panic("invalid epoch") - } - - id := voteID(epoch, candidates) - n := vote(ctx, curEpoch, id, key) - - if n >= threshold { - candidate := candidates[index%len(candidates)] - address := runtime.GetExecutingScriptHash() - - ok := contract.Call([]byte(neoHash), "vote", address, candidate).(bool) - if ok { - runtime.Log(name + ": successfully voted for validator") - removeVotes(ctx, id) - } else { - runtime.Log(name + ": vote has been failed") - } - } else { - runtime.Log(name + ": saved vote for validator") - } - - return -} - -func Name() string { - return name -} - -func vote(ctx storage.Context, epoch int, id, from []byte) int { - var ( - newCandidates []ballot - candidates = getBallots(ctx) - found = -1 - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if bytesEqual(cnd.id, id) { - voters := cnd.n - - for j := range voters { - if bytesEqual(voters[j], from) { - return len(voters) - } - } - - voters = append(voters, from) - cnd = ballot{id: id, n: 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, ballot{ - id: id, - n: voters, - height: epoch}) - found = 1 - } - - setSerialized(ctx, voteKey, newCandidates) - - return found -} - -func removeVotes(ctx storage.Context, id []byte) { - var ( - newCandidates []ballot - candidates = getBallots(ctx) - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if !bytesEqual(cnd.id, id) { - newCandidates = append(newCandidates, cnd) - } - } - - setSerialized(ctx, voteKey, newCandidates) -} - -func getBallots(ctx storage.Context) []ballot { - data := storage.Get(ctx, voteKey) - if data != nil { - return binary.Deserialize(data.([]byte)).([]ballot) - } - - return []ballot{} -} - -func setSerialized(ctx storage.Context, key interface{}, value interface{}) { - data := binary.Serialize(value) - storage.Put(ctx, key, data) -} - -// neo-go#1176 -func bytesEqual(a []byte, b []byte) bool { - return util.Equals(string(a), string(b)) -} - -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) -} diff --git a/alphabet/glagoli/glagoli_contract.go b/alphabet/glagoli/glagoli_contract.go deleted file mode 100644 index 1975d20..0000000 --- a/alphabet/glagoli/glagoli_contract.go +++ /dev/null @@ -1,287 +0,0 @@ -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/runtime" - "github.com/nspcc-dev/neo-go/pkg/interop/storage" - "github.com/nspcc-dev/neo-go/pkg/interop/util" -) - -type ( - irNode struct { - key []byte - } - - ballot struct { - id []byte // hash of validators list - n [][]byte // already voted inner ring nodes - height int // height is an neofs epoch when ballot was registered - } -) - -const ( - // native gas token script hash - gasHash = "\x20\x2a\x2d\xd3\xf6\xa6\xe8\xf4\xd3\xb5\xaf\x26\xa7\xfe\xde\xba\x4b\x80\xdf\xb5" - - // native neo token script hash - neoHash = "\xb9\x7b\x8d\x5a\x73\x11\x81\x6f\xf7\xb1\xbf\xb0\x14\x20\xe2\x59\x0d\xa3\xc1\x24" - - name = "Glagoli" - index = 3 - - netmapContractKey = "netmapScriptHash" - - threshold = totalAlphabetContracts*2/3 + 1 - voteKey = "ballots" - - totalAlphabetContracts = 7 -) - -var ( - ctx storage.Context -) - -func init() { - if runtime.GetTrigger() != runtime.Application { - panic("contract has not been called in application node") - } - - ctx = storage.GetContext() -} - -// OnPayment is a callback for NEP-17 compatible native GAS and NEO contracts. -func OnPayment(from interop.Hash160, amount int, data interface{}) { - caller := runtime.GetCallingScriptHash() - if !bytesEqual(caller, []byte(gasHash)) && !bytesEqual(caller, []byte(neoHash)) { - panic("onPayment: alphabet contract accepts GAS and NEO only") - } -} - -func Init(addrNetmap []byte) { - if storage.Get(ctx, netmapContractKey) != nil { - panic("contract already deployed") - } - - if len(addrNetmap) != 20 { - panic("incorrect length of contract script hash") - } - - storage.Put(ctx, netmapContractKey, addrNetmap) - - setSerialized(ctx, voteKey, []ballot{}) - - runtime.Log(name + " contract initialized") -} - -func Gas() int { - contractHash := runtime.GetExecutingScriptHash() - return balance(gasHash, contractHash) -} - -func Neo() int { - contractHash := runtime.GetExecutingScriptHash() - return balance(neoHash, contractHash) -} - -func balance(hash string, addr []byte) int { - balance := contract.Call([]byte(hash), "balanceOf", addr) - return balance.(int) -} - -func irList() []irNode { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) - return contract.Call(netmapContractAddr, "innerRingList").([]irNode) -} - -func currentEpoch() int { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) - return contract.Call(netmapContractAddr, "epoch").(int) -} - -func checkPermission(ir []irNode) bool { - if len(ir) <= index { - return false - } - - node := ir[index] - return runtime.CheckWitness(node.key) -} - -func innerRingInvoker(ir []irNode) []byte { - for i := 0; i < len(ir); i++ { - if i >= totalAlphabetContracts { - return nil - } - - node := ir[i] - if runtime.CheckWitness(node.key) { - return node.key - } - } - - return nil -} - -func Emit() bool { - innerRingKeys := irList() - if !checkPermission(innerRingKeys) { - panic("invalid invoker") - } - - contractHash := runtime.GetExecutingScriptHash() - neo := balance(neoHash, contractHash) - - _ = contract.Call([]byte(neoHash), "transfer", contractHash, contractHash, neo, nil) - - gas := balance(gasHash, contractHash) - gasPerNode := gas * 7 / 8 / len(innerRingKeys) - - if gasPerNode == 0 { - runtime.Log("no gas to emit") - return false - } - - for i := range innerRingKeys { - node := innerRingKeys[i] - address := contract.CreateStandardAccount(node.key) - - _ = contract.Call([]byte(gasHash), "transfer", contractHash, address, gasPerNode, nil) - } - - runtime.Log("utility token has been emitted to inner ring nodes") - return true -} - -func Vote(epoch int, candidates [][]byte) { - innerRingKeys := irList() - - key := innerRingInvoker(innerRingKeys) - if len(key) == 0 { - panic("invalid invoker") - } - - curEpoch := currentEpoch() - if epoch != curEpoch { - panic("invalid epoch") - } - - id := voteID(epoch, candidates) - n := vote(ctx, curEpoch, id, key) - - if n >= threshold { - candidate := candidates[index%len(candidates)] - address := runtime.GetExecutingScriptHash() - - ok := contract.Call([]byte(neoHash), "vote", address, candidate).(bool) - if ok { - runtime.Log(name + ": successfully voted for validator") - removeVotes(ctx, id) - } else { - runtime.Log(name + ": vote has been failed") - } - } else { - runtime.Log(name + ": saved vote for validator") - } - - return -} - -func Name() string { - return name -} - -func vote(ctx storage.Context, epoch int, id, from []byte) int { - var ( - newCandidates []ballot - candidates = getBallots(ctx) - found = -1 - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if bytesEqual(cnd.id, id) { - voters := cnd.n - - for j := range voters { - if bytesEqual(voters[j], from) { - return len(voters) - } - } - - voters = append(voters, from) - cnd = ballot{id: id, n: 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, ballot{ - id: id, - n: voters, - height: epoch}) - found = 1 - } - - setSerialized(ctx, voteKey, newCandidates) - - return found -} - -func removeVotes(ctx storage.Context, id []byte) { - var ( - newCandidates []ballot - candidates = getBallots(ctx) - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if !bytesEqual(cnd.id, id) { - newCandidates = append(newCandidates, cnd) - } - } - - setSerialized(ctx, voteKey, newCandidates) -} - -func getBallots(ctx storage.Context) []ballot { - data := storage.Get(ctx, voteKey) - if data != nil { - return binary.Deserialize(data.([]byte)).([]ballot) - } - - return []ballot{} -} - -func setSerialized(ctx storage.Context, key interface{}, value interface{}) { - data := binary.Serialize(value) - storage.Put(ctx, key, data) -} - -// neo-go#1176 -func bytesEqual(a []byte, b []byte) bool { - return util.Equals(string(a), string(b)) -} - -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) -} diff --git a/alphabet/jest/jest_contract.go b/alphabet/jest/jest_contract.go deleted file mode 100644 index e355ba0..0000000 --- a/alphabet/jest/jest_contract.go +++ /dev/null @@ -1,287 +0,0 @@ -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/runtime" - "github.com/nspcc-dev/neo-go/pkg/interop/storage" - "github.com/nspcc-dev/neo-go/pkg/interop/util" -) - -type ( - irNode struct { - key []byte - } - - ballot struct { - id []byte // hash of validators list - n [][]byte // already voted inner ring nodes - height int // height is an neofs epoch when ballot was registered - } -) - -const ( - // native gas token script hash - gasHash = "\x20\x2a\x2d\xd3\xf6\xa6\xe8\xf4\xd3\xb5\xaf\x26\xa7\xfe\xde\xba\x4b\x80\xdf\xb5" - - // native neo token script hash - neoHash = "\xb9\x7b\x8d\x5a\x73\x11\x81\x6f\xf7\xb1\xbf\xb0\x14\x20\xe2\x59\x0d\xa3\xc1\x24" - - name = "Jest" - index = 5 - - netmapContractKey = "netmapScriptHash" - - threshold = totalAlphabetContracts*2/3 + 1 - voteKey = "ballots" - - totalAlphabetContracts = 7 -) - -var ( - ctx storage.Context -) - -func init() { - if runtime.GetTrigger() != runtime.Application { - panic("contract has not been called in application node") - } - - ctx = storage.GetContext() -} - -// OnPayment is a callback for NEP-17 compatible native GAS and NEO contracts. -func OnPayment(from interop.Hash160, amount int, data interface{}) { - caller := runtime.GetCallingScriptHash() - if !bytesEqual(caller, []byte(gasHash)) && !bytesEqual(caller, []byte(neoHash)) { - panic("onPayment: alphabet contract accepts GAS and NEO only") - } -} - -func Init(addrNetmap []byte) { - if storage.Get(ctx, netmapContractKey) != nil { - panic("contract already deployed") - } - - if len(addrNetmap) != 20 { - panic("incorrect length of contract script hash") - } - - storage.Put(ctx, netmapContractKey, addrNetmap) - - setSerialized(ctx, voteKey, []ballot{}) - - runtime.Log(name + " contract initialized") -} - -func Gas() int { - contractHash := runtime.GetExecutingScriptHash() - return balance(gasHash, contractHash) -} - -func Neo() int { - contractHash := runtime.GetExecutingScriptHash() - return balance(neoHash, contractHash) -} - -func balance(hash string, addr []byte) int { - balance := contract.Call([]byte(hash), "balanceOf", addr) - return balance.(int) -} - -func irList() []irNode { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) - return contract.Call(netmapContractAddr, "innerRingList").([]irNode) -} - -func currentEpoch() int { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) - return contract.Call(netmapContractAddr, "epoch").(int) -} - -func checkPermission(ir []irNode) bool { - if len(ir) <= index { - return false - } - - node := ir[index] - return runtime.CheckWitness(node.key) -} - -func innerRingInvoker(ir []irNode) []byte { - for i := 0; i < len(ir); i++ { - if i >= totalAlphabetContracts { - return nil - } - - node := ir[i] - if runtime.CheckWitness(node.key) { - return node.key - } - } - - return nil -} - -func Emit() bool { - innerRingKeys := irList() - if !checkPermission(innerRingKeys) { - panic("invalid invoker") - } - - contractHash := runtime.GetExecutingScriptHash() - neo := balance(neoHash, contractHash) - - _ = contract.Call([]byte(neoHash), "transfer", contractHash, contractHash, neo, nil) - - gas := balance(gasHash, contractHash) - gasPerNode := gas * 7 / 8 / len(innerRingKeys) - - if gasPerNode == 0 { - runtime.Log("no gas to emit") - return false - } - - for i := range innerRingKeys { - node := innerRingKeys[i] - address := contract.CreateStandardAccount(node.key) - - _ = contract.Call([]byte(gasHash), "transfer", contractHash, address, gasPerNode, nil) - } - - runtime.Log("utility token has been emitted to inner ring nodes") - return true -} - -func Vote(epoch int, candidates [][]byte) { - innerRingKeys := irList() - - key := innerRingInvoker(innerRingKeys) - if len(key) == 0 { - panic("invalid invoker") - } - - curEpoch := currentEpoch() - if epoch != curEpoch { - panic("invalid epoch") - } - - id := voteID(epoch, candidates) - n := vote(ctx, curEpoch, id, key) - - if n >= threshold { - candidate := candidates[index%len(candidates)] - address := runtime.GetExecutingScriptHash() - - ok := contract.Call([]byte(neoHash), "vote", address, candidate).(bool) - if ok { - runtime.Log(name + ": successfully voted for validator") - removeVotes(ctx, id) - } else { - runtime.Log(name + ": vote has been failed") - } - } else { - runtime.Log(name + ": saved vote for validator") - } - - return -} - -func Name() string { - return name -} - -func vote(ctx storage.Context, epoch int, id, from []byte) int { - var ( - newCandidates []ballot - candidates = getBallots(ctx) - found = -1 - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if bytesEqual(cnd.id, id) { - voters := cnd.n - - for j := range voters { - if bytesEqual(voters[j], from) { - return len(voters) - } - } - - voters = append(voters, from) - cnd = ballot{id: id, n: 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, ballot{ - id: id, - n: voters, - height: epoch}) - found = 1 - } - - setSerialized(ctx, voteKey, newCandidates) - - return found -} - -func removeVotes(ctx storage.Context, id []byte) { - var ( - newCandidates []ballot - candidates = getBallots(ctx) - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if !bytesEqual(cnd.id, id) { - newCandidates = append(newCandidates, cnd) - } - } - - setSerialized(ctx, voteKey, newCandidates) -} - -func getBallots(ctx storage.Context) []ballot { - data := storage.Get(ctx, voteKey) - if data != nil { - return binary.Deserialize(data.([]byte)).([]ballot) - } - - return []ballot{} -} - -func setSerialized(ctx storage.Context, key interface{}, value interface{}) { - data := binary.Serialize(value) - storage.Put(ctx, key, data) -} - -// neo-go#1176 -func bytesEqual(a []byte, b []byte) bool { - return util.Equals(string(a), string(b)) -} - -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) -} diff --git a/alphabet/vedi/vedi_contract.go b/alphabet/vedi/vedi_contract.go deleted file mode 100644 index 1c8daa6..0000000 --- a/alphabet/vedi/vedi_contract.go +++ /dev/null @@ -1,287 +0,0 @@ -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/runtime" - "github.com/nspcc-dev/neo-go/pkg/interop/storage" - "github.com/nspcc-dev/neo-go/pkg/interop/util" -) - -type ( - irNode struct { - key []byte - } - - ballot struct { - id []byte // hash of validators list - n [][]byte // already voted inner ring nodes - height int // height is an neofs epoch when ballot was registered - } -) - -const ( - // native gas token script hash - gasHash = "\x20\x2a\x2d\xd3\xf6\xa6\xe8\xf4\xd3\xb5\xaf\x26\xa7\xfe\xde\xba\x4b\x80\xdf\xb5" - - // native neo token script hash - neoHash = "\xb9\x7b\x8d\x5a\x73\x11\x81\x6f\xf7\xb1\xbf\xb0\x14\x20\xe2\x59\x0d\xa3\xc1\x24" - - name = "Vedi" - index = 2 - - netmapContractKey = "netmapScriptHash" - - threshold = totalAlphabetContracts*2/3 + 1 - voteKey = "ballots" - - totalAlphabetContracts = 7 -) - -var ( - ctx storage.Context -) - -func init() { - if runtime.GetTrigger() != runtime.Application { - panic("contract has not been called in application node") - } - - ctx = storage.GetContext() -} - -// OnPayment is a callback for NEP-17 compatible native GAS and NEO contracts. -func OnPayment(from interop.Hash160, amount int, data interface{}) { - caller := runtime.GetCallingScriptHash() - if !bytesEqual(caller, []byte(gasHash)) && !bytesEqual(caller, []byte(neoHash)) { - panic("onPayment: alphabet contract accepts GAS and NEO only") - } -} - -func Init(addrNetmap []byte) { - if storage.Get(ctx, netmapContractKey) != nil { - panic("contract already deployed") - } - - if len(addrNetmap) != 20 { - panic("incorrect length of contract script hash") - } - - storage.Put(ctx, netmapContractKey, addrNetmap) - - setSerialized(ctx, voteKey, []ballot{}) - - runtime.Log(name + " contract initialized") -} - -func Gas() int { - contractHash := runtime.GetExecutingScriptHash() - return balance(gasHash, contractHash) -} - -func Neo() int { - contractHash := runtime.GetExecutingScriptHash() - return balance(neoHash, contractHash) -} - -func balance(hash string, addr []byte) int { - balance := contract.Call([]byte(hash), "balanceOf", addr) - return balance.(int) -} - -func irList() []irNode { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) - return contract.Call(netmapContractAddr, "innerRingList").([]irNode) -} - -func currentEpoch() int { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) - return contract.Call(netmapContractAddr, "epoch").(int) -} - -func checkPermission(ir []irNode) bool { - if len(ir) <= index { - return false - } - - node := ir[index] - return runtime.CheckWitness(node.key) -} - -func innerRingInvoker(ir []irNode) []byte { - for i := 0; i < len(ir); i++ { - if i >= totalAlphabetContracts { - return nil - } - - node := ir[i] - if runtime.CheckWitness(node.key) { - return node.key - } - } - - return nil -} - -func Emit() bool { - innerRingKeys := irList() - if !checkPermission(innerRingKeys) { - panic("invalid invoker") - } - - contractHash := runtime.GetExecutingScriptHash() - neo := balance(neoHash, contractHash) - - _ = contract.Call([]byte(neoHash), "transfer", contractHash, contractHash, neo, nil) - - gas := balance(gasHash, contractHash) - gasPerNode := gas * 7 / 8 / len(innerRingKeys) - - if gasPerNode == 0 { - runtime.Log("no gas to emit") - return false - } - - for i := range innerRingKeys { - node := innerRingKeys[i] - address := contract.CreateStandardAccount(node.key) - - _ = contract.Call([]byte(gasHash), "transfer", contractHash, address, gasPerNode, nil) - } - - runtime.Log("utility token has been emitted to inner ring nodes") - return true -} - -func Vote(epoch int, candidates [][]byte) { - innerRingKeys := irList() - - key := innerRingInvoker(innerRingKeys) - if len(key) == 0 { - panic("invalid invoker") - } - - curEpoch := currentEpoch() - if epoch != curEpoch { - panic("invalid epoch") - } - - id := voteID(epoch, candidates) - n := vote(ctx, curEpoch, id, key) - - if n >= threshold { - candidate := candidates[index%len(candidates)] - address := runtime.GetExecutingScriptHash() - - ok := contract.Call([]byte(neoHash), "vote", address, candidate).(bool) - if ok { - runtime.Log(name + ": successfully voted for validator") - removeVotes(ctx, id) - } else { - runtime.Log(name + ": vote has been failed") - } - } else { - runtime.Log(name + ": saved vote for validator") - } - - return -} - -func Name() string { - return name -} - -func vote(ctx storage.Context, epoch int, id, from []byte) int { - var ( - newCandidates []ballot - candidates = getBallots(ctx) - found = -1 - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if bytesEqual(cnd.id, id) { - voters := cnd.n - - for j := range voters { - if bytesEqual(voters[j], from) { - return len(voters) - } - } - - voters = append(voters, from) - cnd = ballot{id: id, n: 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, ballot{ - id: id, - n: voters, - height: epoch}) - found = 1 - } - - setSerialized(ctx, voteKey, newCandidates) - - return found -} - -func removeVotes(ctx storage.Context, id []byte) { - var ( - newCandidates []ballot - candidates = getBallots(ctx) - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if !bytesEqual(cnd.id, id) { - newCandidates = append(newCandidates, cnd) - } - } - - setSerialized(ctx, voteKey, newCandidates) -} - -func getBallots(ctx storage.Context) []ballot { - data := storage.Get(ctx, voteKey) - if data != nil { - return binary.Deserialize(data.([]byte)).([]ballot) - } - - return []ballot{} -} - -func setSerialized(ctx storage.Context, key interface{}, value interface{}) { - data := binary.Serialize(value) - storage.Put(ctx, key, data) -} - -// neo-go#1176 -func bytesEqual(a []byte, b []byte) bool { - return util.Equals(string(a), string(b)) -} - -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) -} diff --git a/alphabet/zhivete/zhivete_contract.go b/alphabet/zhivete/zhivete_contract.go deleted file mode 100644 index 58b4b6a..0000000 --- a/alphabet/zhivete/zhivete_contract.go +++ /dev/null @@ -1,287 +0,0 @@ -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/runtime" - "github.com/nspcc-dev/neo-go/pkg/interop/storage" - "github.com/nspcc-dev/neo-go/pkg/interop/util" -) - -type ( - irNode struct { - key []byte - } - - ballot struct { - id []byte // hash of validators list - n [][]byte // already voted inner ring nodes - height int // height is an neofs epoch when ballot was registered - } -) - -const ( - // native gas token script hash - gasHash = "\x20\x2a\x2d\xd3\xf6\xa6\xe8\xf4\xd3\xb5\xaf\x26\xa7\xfe\xde\xba\x4b\x80\xdf\xb5" - - // native neo token script hash - neoHash = "\xb9\x7b\x8d\x5a\x73\x11\x81\x6f\xf7\xb1\xbf\xb0\x14\x20\xe2\x59\x0d\xa3\xc1\x24" - - name = "Zhivete" - index = 6 - - netmapContractKey = "netmapScriptHash" - - threshold = totalAlphabetContracts*2/3 + 1 - voteKey = "ballots" - - totalAlphabetContracts = 7 -) - -var ( - ctx storage.Context -) - -func init() { - if runtime.GetTrigger() != runtime.Application { - panic("contract has not been called in application node") - } - - ctx = storage.GetContext() -} - -// OnPayment is a callback for NEP-17 compatible native GAS and NEO contracts. -func OnPayment(from interop.Hash160, amount int, data interface{}) { - caller := runtime.GetCallingScriptHash() - if !bytesEqual(caller, []byte(gasHash)) && !bytesEqual(caller, []byte(neoHash)) { - panic("onPayment: alphabet contract accepts GAS and NEO only") - } -} - -func Init(addrNetmap []byte) { - if storage.Get(ctx, netmapContractKey) != nil { - panic("contract already deployed") - } - - if len(addrNetmap) != 20 { - panic("incorrect length of contract script hash") - } - - storage.Put(ctx, netmapContractKey, addrNetmap) - - setSerialized(ctx, voteKey, []ballot{}) - - runtime.Log(name + " contract initialized") -} - -func Gas() int { - contractHash := runtime.GetExecutingScriptHash() - return balance(gasHash, contractHash) -} - -func Neo() int { - contractHash := runtime.GetExecutingScriptHash() - return balance(neoHash, contractHash) -} - -func balance(hash string, addr []byte) int { - balance := contract.Call([]byte(hash), "balanceOf", addr) - return balance.(int) -} - -func irList() []irNode { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) - return contract.Call(netmapContractAddr, "innerRingList").([]irNode) -} - -func currentEpoch() int { - netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte) - return contract.Call(netmapContractAddr, "epoch").(int) -} - -func checkPermission(ir []irNode) bool { - if len(ir) <= index { - return false - } - - node := ir[index] - return runtime.CheckWitness(node.key) -} - -func innerRingInvoker(ir []irNode) []byte { - for i := 0; i < len(ir); i++ { - if i >= totalAlphabetContracts { - return nil - } - - node := ir[i] - if runtime.CheckWitness(node.key) { - return node.key - } - } - - return nil -} - -func Emit() bool { - innerRingKeys := irList() - if !checkPermission(innerRingKeys) { - panic("invalid invoker") - } - - contractHash := runtime.GetExecutingScriptHash() - neo := balance(neoHash, contractHash) - - _ = contract.Call([]byte(neoHash), "transfer", contractHash, contractHash, neo, nil) - - gas := balance(gasHash, contractHash) - gasPerNode := gas * 7 / 8 / len(innerRingKeys) - - if gasPerNode == 0 { - runtime.Log("no gas to emit") - return false - } - - for i := range innerRingKeys { - node := innerRingKeys[i] - address := contract.CreateStandardAccount(node.key) - - _ = contract.Call([]byte(gasHash), "transfer", contractHash, address, gasPerNode, nil) - } - - runtime.Log("utility token has been emitted to inner ring nodes") - return true -} - -func Vote(epoch int, candidates [][]byte) { - innerRingKeys := irList() - - key := innerRingInvoker(innerRingKeys) - if len(key) == 0 { - panic("invalid invoker") - } - - curEpoch := currentEpoch() - if epoch != curEpoch { - panic("invalid epoch") - } - - id := voteID(epoch, candidates) - n := vote(ctx, curEpoch, id, key) - - if n >= threshold { - candidate := candidates[index%len(candidates)] - address := runtime.GetExecutingScriptHash() - - ok := contract.Call([]byte(neoHash), "vote", address, candidate).(bool) - if ok { - runtime.Log(name + ": successfully voted for validator") - removeVotes(ctx, id) - } else { - runtime.Log(name + ": vote has been failed") - } - } else { - runtime.Log(name + ": saved vote for validator") - } - - return -} - -func Name() string { - return name -} - -func vote(ctx storage.Context, epoch int, id, from []byte) int { - var ( - newCandidates []ballot - candidates = getBallots(ctx) - found = -1 - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if bytesEqual(cnd.id, id) { - voters := cnd.n - - for j := range voters { - if bytesEqual(voters[j], from) { - return len(voters) - } - } - - voters = append(voters, from) - cnd = ballot{id: id, n: 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, ballot{ - id: id, - n: voters, - height: epoch}) - found = 1 - } - - setSerialized(ctx, voteKey, newCandidates) - - return found -} - -func removeVotes(ctx storage.Context, id []byte) { - var ( - newCandidates []ballot - candidates = getBallots(ctx) - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if !bytesEqual(cnd.id, id) { - newCandidates = append(newCandidates, cnd) - } - } - - setSerialized(ctx, voteKey, newCandidates) -} - -func getBallots(ctx storage.Context) []ballot { - data := storage.Get(ctx, voteKey) - if data != nil { - return binary.Deserialize(data.([]byte)).([]ballot) - } - - return []ballot{} -} - -func setSerialized(ctx storage.Context, key interface{}, value interface{}) { - data := binary.Serialize(value) - storage.Put(ctx, key, data) -} - -// neo-go#1176 -func bytesEqual(a []byte, b []byte) bool { - return util.Equals(string(a), string(b)) -} - -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) -}