Skip to content

Commit

Permalink
feat: github oracle
Browse files Browse the repository at this point in the history
  • Loading branch information
omarsy committed Apr 20, 2024
1 parent 4470e0e commit 624b1fc
Show file tree
Hide file tree
Showing 9 changed files with 371 additions and 0 deletions.
44 changes: 44 additions & 0 deletions examples/gno.land/r/demo/teritori/gh/CMD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
gnokey maketx addpkg \
-deposit="1ugnot" \
-gas-fee="1ugnot" \
-gas-wanted="5000000" \
-broadcast="true" \
-remote="https://rpc.gno.land:443" \
-chainid="portal-loop" \
-pkgdir="." \
-pkgpath="gno.land/r/mikecito/gh_test_4" \
mykey2

gnokey maketx call \
-gas-fee="1ugnot" \
-gas-wanted="5000000" \
-broadcast="true" \
-remote="https://rpc.gno.land:443" \
-chainid="portal-loop" \
-pkgpath="gno.land/r/mikecito/gh_test_4" \
-func="AdminSetOracleAddr" \
-args="g1d46t4el0dduffs5j56t2razaeyvnmkxlduduuw" \
mykey2

gnokey maketx call \
-gas-fee="1ugnot" \
-gas-wanted="5000000" \
-broadcast="true" \
-remote="https://rpc.gno.land:443" \
-chainid="portal-loop" \
-pkgpath="gno.land/r/mikecito/gh_test_4" \
-func="OracleUpsertAccount" \
-args="15034695" \
-args="omarsy" \
-args="6h057" \
-args="user" \
mykey2

gnokey query "vm/qeval" -data='gno.land/r/mikecito/gh_test_4
AccountByID("15034695")' -remote="https://rpc.gno.land:443"

gnokey query "vm/qeval" -data='gno.land/r/mikecito/gh_test_4
RenderAccount("g14mfv59k38r8k5vkevpu0lpqlqra0e9trwp3d32")' -remote="https://rpc.gno.land:443"

gnokey query "vm/qeval" -data='gno.land/r/mikecito/gh_test_4
Render()' -remote="https://rpc.gno.land:443"
66 changes: 66 additions & 0 deletions examples/gno.land/r/demo/teritori/gh/account.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package gh

import (
"errors"
"std"

"gno.land/p/demo/avl"
)

// Account represents a GitHub user account or organization.
type Account struct {
id string
login string
name string
kind string
}

func (a Account) ID() string { return a.id }
func (a Account) Name() string { return a.name }
func (a Account) Kind() string { return a.kind }
func (a Account) URL() string { return "https://github.com/" + a.login }
func (a Account) IsUser() bool { return a.kind == UserAccount }
func (a Account) IsOrg() bool { return a.kind == OrgAccount }

// TODO: func (a Account) RepoByID() Repo ...

func (a Account) Validate() error {
if a.id == "" {
return errors.New("empty id")
}

if a.login == "" {
return errors.New("empty login")
}
if a.kind == "" || (a.kind != UserAccount && a.kind != OrgAccount) {
return errors.New("empty kind")
}
if a.name == "" {
return errors.New("empty name")
}
// TODO: validate
return nil
}

func (a Account) Render() string {
return `{ "id": "` + a.id + `", "login": "` + a.login + `", "name": "` + a.name + `", "kind": "` + a.kind + `" }`
}

func (a Account) String() string {
// XXX: better idea?
return a.URL()
}

const (
UserAccount string = "user"
OrgAccount string = "org"
)

func AccountByID(id string) *Account {
res, ok := accounts.Get(id)
if !ok {
return nil
}

return res.(*Account)
}
25 changes: 25 additions & 0 deletions examples/gno.land/r/demo/teritori/gh/admin.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package gh

import (
"std"
)

var(
adminAddr std.Address = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq"
)


func assertIsAdmin() {
if std.GetOrigCaller() != adminAddr {
panic("restricted area")
}
}

func setAdminAddress(address std.Address) {
adminAddr = address
}

func SetAdminAddress(address std.Address) {
assertIsAdmin()
setAdminAddress(address)
}
22 changes: 22 additions & 0 deletions examples/gno.land/r/demo/teritori/gh/admin_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package gh

import (
"std"
"testing"

"gno.land/p/demo/avl"
"gno.land/p/demo/testutils"
)

func TestAssertIsAdmin(t *testing.T) {
adminAddr = "g1test1234"
randomuser := testutils.TestAddress("g1unknown_player")
defer func() {
if r := recover(); r != nil {
}
}()
std.TestSetOrigCaller(randomuser)
assertIsAdmin()
t.Fatalf("should fail because not admin")
}

6 changes: 6 additions & 0 deletions examples/gno.land/r/demo/teritori/gh/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module gno.land/r/demo/teritori/gh

require (
gno.land/p/demo/avl v0.0.0-latest
)

54 changes: 54 additions & 0 deletions examples/gno.land/r/demo/teritori/gh/oracle.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package gh

import (
"std"
"strings"
"time"

"gno.land/p/demo/avl"
)

var (
accounts avl.Tree // id -> Account
lastUpdateTime time.Time // used by the bot to only upload the diff
oracleAddr std.Address
)

func OracleLastUpdated() time.Time { return lastUpdateTime }

func OracleUpsertAccount(id, login, name, kind string) {
assertIsOracle()
lastUpdateTime = time.Now()

// get or create
account := &Account{}
res, ok := accounts.Get(id)
if ok {
account = res.(*Account)
} else {
account.id = id
}

// update fields
account.name = name
account.kind = kind
account.login = login

if err := account.Validate(); err != nil {
panic(err)
}

// save
accounts.Set(id, account)
}

func AdminSetOracleAddr(new std.Address) {
assertIsAdmin()
oracleAddr = new
}

func assertIsOracle() {
if std.GetOrigCaller() != oracleAddr {
panic("restricted area")
}
}
60 changes: 60 additions & 0 deletions examples/gno.land/r/demo/teritori/gh/oracle_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package gh

import (
"std"
"testing"
"time"

"gno.land/p/demo/avl"
"gno.land/p/demo/testutils"
)

func TestOracleUpsertUserIsNotOracle(t *testing.T) {
oracleAddr = "g1test1234"
var randomuser = "g1unknown_player"
user := testutils.TestAddress("user")
defer func() {
if r := recover(); r != nil {
}
}()
OracleUpsertAccount("acountID", "villaquiranm","john doe","user")
t.Fatalf("should fail because not admin")
}

func TestOracleUpsertUserOk(t *testing.T) {
oracleAddr = "g1random"
if accounts.Size() != 0 {
t.Fatalf("Accounts is not empty")
}
now := time.Now()

std.TestSetOrigCaller(oracleAddr)

var randomuser = "g1unknown_player"
OracleUpsertAccount("acountID", "villaquiranm","john doe","user")

if accounts.Size() != 1 {
t.Fatalf("User was not created")
}

OracleUpsertAccount("acountID", "villaquiranm","john doe","user")

if accounts.Size() != 1 {
t.Fatalf("User was created more than once")
}

if OracleLastUpdated().Unix() < now.Unix() {
t.Fatalf("OracleLastUpdated was not changed")
}
}

func TestAssertIsOracle(t *testing.T) {
std.TestSetOrigCaller(adminAddr)
AdminSetOracleAddr("g1random123")
defer func() {
if r := recover(); r != nil {
}
}()
assertIsOracle()
t.Fatalf("should fail because user is not oracle")
}
63 changes: 63 additions & 0 deletions examples/gno.land/r/demo/teritori/gh/public.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package gh

import (
"std"

"gno.land/p/demo/avl"
)

var (
addressToAccount avl.Tree // address -> Account
guardian std.Address // guardian address
)

func init() {
addressToAccount = avl.Tree{}
setAdminAddress(std.GetOrigCaller())
}

// Todo maybe we should gave multi guardian
func SetGuardian(address std.Address) {
assertIsAdmin()
guardian = address
}

func LinkAccount(accountID string, address std.Address, signature string) {
verifySignature(accountID+" "+address.String(), signature)

account := AccountByID(accountID)
if account == nil {
panic("account not found")
}

addressToAccount.Set(address.String(), account)
}

func RenderAccount(address std.Address) string {
account, ok := addressToAccount.Get(address.String())
if !ok {
panic("account not found")
}

return account.(*Account).Render()
}

func Render(address string) string {
if address != "" {
return RenderAccount(std.Address(address))
}
str := "["
addressToAccount.Iterate("", "", func(key string, value interface{}) bool {
account := value.(*Account)
str += account.Render()
str += ","
return false
})
str += "]"

return str
}

func verifySignature(message, signature string) bool {
return true
}
31 changes: 31 additions & 0 deletions examples/gno.land/r/demo/teritori/gh/public_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package gh

import (
"std"
"testing"

"gno.land/p/demo/avl"
"gno.land/p/demo/testutils"
)

func TestLinkAccount(t *testing.T) {
adminAddr = "g1test1234"

user := testutils.TestAddress("user")
admin := testutils.TestAddress("admin")

std.TestSetOrigCaller(admin)
setAdminAddress(admin)
AdminSetOracleAddr(admin)

OracleUpsertAccount("123","user", "user", UserAccount)
LinkAccount("123", user, "signature")
accountInPublic, ok := addressToAccount.Get(user.String())
if !ok {
t.Fatalf("account not found")
}
account := AccountByID("123")
if accountInPublic != account {
t.Fatalf("account is not same")
}
}

0 comments on commit 624b1fc

Please sign in to comment.