Skip to content

Commit

Permalink
feat(stdlibs/std): restrict Banker methods based on caller of GetBank…
Browse files Browse the repository at this point in the history
…er (#1921)

related pr #1787

There was bit of extra conversion in previous pr after merged. 
1) revert test cases
2) allow `Send` from realm that created banker rather the one calling

<!-- please provide a detailed description of the changes made in this
pull request. -->

<details><summary>Contributors' checklist...</summary>

- [x] Added new tests, or not needed, or not feasible
- [x] Provided an example (e.g. screenshot) to aid review or the PR is
self-explanatory
- [x] Updated the official documentation or not needed
- [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message
was included in the description
- [x] Added references to related issues and PRs
- [ ] Provided any useful hints for running manual tests
- [ ] Added new benchmarks to [generated
graphs](https://gnoland.github.io/benchmarks), if any. More info
[here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
</details>

---------

Co-authored-by: Morgan <git@howl.moe>
  • Loading branch information
r3v4s and thehowl authored Jul 2, 2024
1 parent 981f3fa commit 876eaf9
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 58 deletions.
2 changes: 1 addition & 1 deletion docs/concepts/stdlibs/coin.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ which can manipulate them depending on access rights.

Read more about coins in the [Effective Gno](../effective-gno.md#coins) section.

The Coin(s) API can be found in under the `std` package [reference](../../reference/stdlibs/std/coin.md).
The Coin(s) API can be found in under the `std` package [reference](../../reference/stdlibs/std/coin.md).
2 changes: 1 addition & 1 deletion examples/gno.land/r/demo/banktest/banktest.gno
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func Deposit(returnDenom string, returnAmount int64) string {
// return if any.
if returnAmount > 0 {
banker := std.GetBanker(std.BankerTypeOrigSend)
pkgaddr := std.CurrentRealm().Addr()
pkgaddr := std.GetOrigPkgAddr()
// TODO: use std.Coins constructors, this isn't generally safe.
banker.SendCoins(pkgaddr, caller, send)
return "returned!"
Expand Down
35 changes: 18 additions & 17 deletions examples/gno.land/r/demo/banktest/z_0_filetest.gno
Original file line number Diff line number Diff line change
@@ -1,47 +1,48 @@
package main

// NOTE: this doesn't do anything, as it sends to "main".
// SEND: 100000000ugnot

package main

import (
"std"

"gno.land/r/demo/banktest"
)

func main() {
// set up main address and banktest addr.
banktestAddr := std.DerivePkgAddr("gno.land/r/demo/banktest")

// print main balance before.
mainaddr := std.DerivePkgAddr("main")
std.TestSetOrigCaller(mainaddr)
std.TestSetOrigPkgAddr(banktestAddr)

banker := std.GetBanker(std.BankerTypeReadonly)
// get and print balance of mainaddr.
// with the SEND, + 200 gnot given by the TestContext, main should have 300gnot.
banker := std.GetBanker(std.BankerTypeRealmSend)
mainbal := banker.GetCoins(mainaddr)
println("main before:", mainbal) // plus OrigSend equals 300.
println("main before:", mainbal)

// simulate a Deposit call.
std.TestIssueCoins(banktestAddr, std.Coins{{"ugnot", 100000000}})
std.TestSetOrigSend(std.Coins{{"ugnot", 100000000}}, nil)
res := banktest.Deposit("ugnot", 100000000)
// simulate a Deposit call. use Send + OrigSend to simulate -send.
banker.SendCoins(mainaddr, banktestAddr, std.Coins{{"ugnot", 100_000_000}})
std.TestSetOrigSend(std.Coins{{"ugnot", 100_000_000}}, nil)
res := banktest.Deposit("ugnot", 50_000_000)
println("Deposit():", res)

// print main balance after.
mainbal = banker.GetCoins(mainaddr)
println("main after:", mainbal) // still 300.
println("main after:", mainbal)

// simulate a Render().
// simulate a Render(). banker should have given back all coins.
res = banktest.Render("")
println(res)
}

// Output:
// main before: 200000000ugnot
// main before: 300000000ugnot
// Deposit(): returned!
// main after: 300000000ugnot
// main after: 250000000ugnot
// ## recent activity
//
// * g17rgsdnfxzza0sdfsdma37sdwxagsz378833ca4 100000000ugnot sent, 100000000ugnot returned, at 2009-02-13 11:31pm UTC
// * g17rgsdnfxzza0sdfsdma37sdwxagsz378833ca4 100000000ugnot sent, 50000000ugnot returned, at 2009-02-13 11:31pm UTC
//
// ## total deposits
// 300000000ugnot
// 50000000ugnot
1 change: 1 addition & 0 deletions examples/gno.land/r/demo/banktest/z_1_filetest.gno
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ func main() {
banktestAddr := std.DerivePkgAddr("gno.land/r/demo/banktest")

// simulate a Deposit call.
std.TestSetOrigPkgAddr(banktestAddr)
std.TestIssueCoins(banktestAddr, std.Coins{{"ugnot", 100000000}})
std.TestSetOrigSend(std.Coins{{"ugnot", 100000000}}, nil)
res := banktest.Deposit("ugnot", 101000000)
Expand Down
20 changes: 20 additions & 0 deletions examples/gno.land/r/demo/banktest/z_3_filetest.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package main

import (
"std"
)

func main() {
banktestAddr := std.DerivePkgAddr("gno.land/r/demo/banktest")

mainaddr := std.DerivePkgAddr("main")
std.TestSetOrigCaller(mainaddr)

banker := std.GetBanker(std.BankerTypeRealmSend)
send := std.Coins{{"ugnot", 123}}
banker.SendCoins(banktestAddr, mainaddr, send)

}

// Error:
// can only send coins from realm that created banker "g17rgsdnfxzza0sdfsdma37sdwxagsz378833ca4", not "g1dv3435088tlrgggf745kaud0ptrkc9v42k8llz"
32 changes: 13 additions & 19 deletions examples/gno.land/r/demo/wugnot/z0_filetest.gno
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,10 @@ func printBalances() {
printSingleBalance := func(name string, addr std.Address) {
wugnotBal := wugnot.BalanceOf(pusers.AddressOrName(addr))
std.TestSetOrigCaller(addr)
abanker := std.GetBanker(std.BankerTypeOrigSend)
acoins := abanker.GetCoins(addr).AmountOf("ugnot")
bbanker := std.GetBanker(std.BankerTypeRealmIssue)
bcoins := bbanker.GetCoins(addr).AmountOf("ugnot")
cbanker := std.GetBanker(std.BankerTypeRealmSend)
ccoins := cbanker.GetCoins(addr).AmountOf("ugnot")
dbanker := std.GetBanker(std.BankerTypeReadonly)
dcoins := dbanker.GetCoins(addr).AmountOf("ugnot")
fmt.Printf("| %-13s | addr=%s | wugnot=%-5d | ugnot=%-9d %-9d %-9d %-9d |\n",
name, addr, wugnotBal, acoins, bcoins, ccoins, dcoins)
robanker := std.GetBanker(std.BankerTypeReadonly)
coins := robanker.GetCoins(addr).AmountOf("ugnot")
fmt.Printf("| %-13s | addr=%s | wugnot=%-5d | ugnot=%-9d |\n",
name, addr, wugnotBal, coins)
}
println("-----------")
printSingleBalance("wugnot_test", addrt)
Expand All @@ -61,17 +55,17 @@ func printBalances() {

// Output:
// -----------
// | wugnot_test | addr=g19rmydykafrqyyegc8uuaxxpzqwzcnxraj2dev9 | wugnot=0 | ugnot=200000000 200000000 200000000 200000000 |
// | wugnot | addr=g1pf6dv9fjk3rn0m4jjcne306ga4he3mzmupfjl6 | wugnot=0 | ugnot=100000001 100000001 100000001 100000001 |
// | addr1 | addr=g1w3jhxap3ta047h6lta047h6lta047h6l4mfnm7 | wugnot=0 | ugnot=100000001 100000001 100000001 100000001 |
// | wugnot_test | addr=g19rmydykafrqyyegc8uuaxxpzqwzcnxraj2dev9 | wugnot=0 | ugnot=200000000 |
// | wugnot | addr=g1pf6dv9fjk3rn0m4jjcne306ga4he3mzmupfjl6 | wugnot=0 | ugnot=100000001 |
// | addr1 | addr=g1w3jhxap3ta047h6lta047h6lta047h6l4mfnm7 | wugnot=0 | ugnot=100000001 |
// -----------
// -----------
// | wugnot_test | addr=g19rmydykafrqyyegc8uuaxxpzqwzcnxraj2dev9 | wugnot=123400 | ugnot=200000000 200000000 200000000 200000000 |
// | wugnot | addr=g1pf6dv9fjk3rn0m4jjcne306ga4he3mzmupfjl6 | wugnot=0 | ugnot=100000001 100000001 100000001 100000001 |
// | addr1 | addr=g1w3jhxap3ta047h6lta047h6lta047h6l4mfnm7 | wugnot=0 | ugnot=100000001 100000001 100000001 100000001 |
// | wugnot_test | addr=g19rmydykafrqyyegc8uuaxxpzqwzcnxraj2dev9 | wugnot=123400 | ugnot=200000000 |
// | wugnot | addr=g1pf6dv9fjk3rn0m4jjcne306ga4he3mzmupfjl6 | wugnot=0 | ugnot=100000001 |
// | addr1 | addr=g1w3jhxap3ta047h6lta047h6lta047h6l4mfnm7 | wugnot=0 | ugnot=100000001 |
// -----------
// -----------
// | wugnot_test | addr=g19rmydykafrqyyegc8uuaxxpzqwzcnxraj2dev9 | wugnot=119158 | ugnot=200004242 200004242 200004242 200004242 |
// | wugnot | addr=g1pf6dv9fjk3rn0m4jjcne306ga4he3mzmupfjl6 | wugnot=0 | ugnot=99995759 99995759 99995759 99995759 |
// | addr1 | addr=g1w3jhxap3ta047h6lta047h6lta047h6l4mfnm7 | wugnot=0 | ugnot=100000001 100000001 100000001 100000001 |
// | wugnot_test | addr=g19rmydykafrqyyegc8uuaxxpzqwzcnxraj2dev9 | wugnot=119158 | ugnot=200004242 |
// | wugnot | addr=g1pf6dv9fjk3rn0m4jjcne306ga4he3mzmupfjl6 | wugnot=0 | ugnot=99995759 |
// | addr1 | addr=g1w3jhxap3ta047h6lta047h6lta047h6l4mfnm7 | wugnot=0 | ugnot=100000001 |
// -----------
26 changes: 23 additions & 3 deletions gnovm/stdlibs/std/banker.gno
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package std

import "strconv"
import (
"strconv"
)

// Realm functions can call std.GetBanker(options) to get
// a banker instance. Banker objects cannot be persisted,
Expand Down Expand Up @@ -66,7 +68,20 @@ func GetBanker(bt BankerType) Banker {
if bt >= maxBanker {
panic("invalid banker type")
}
return banker{bt}

var pkgAddr Address
if bt == BankerTypeOrigSend {
pkgAddr = GetOrigPkgAddr()
if pkgAddr != CurrentRealm().Addr() {
panic("banker with type BankerTypeOrigSend can only be instantiated by the origin package")
}
} else if bt == BankerTypeRealmSend || bt == BankerTypeRealmIssue {
pkgAddr = CurrentRealm().Addr()
}
return banker{
bt,
pkgAddr,
}
}

// These are native bindings to the banker's functions.
Expand All @@ -77,7 +92,8 @@ func bankerIssueCoin(bt uint8, addr string, denom string, amount int64)
func bankerRemoveCoin(bt uint8, addr string, denom string, amount int64)

type banker struct {
bt BankerType
bt BankerType
pkgAddr Address
}

func (b banker) GetCoins(addr Address) (dst Coins) {
Expand All @@ -93,6 +109,10 @@ func (b banker) SendCoins(from, to Address, amt Coins) {
if b.bt == BankerTypeReadonly {
panic("BankerTypeReadonly cannot send coins")
}
if b.pkgAddr != from {
msg := `can only send coins from realm that created banker "` + b.pkgAddr + `", not "` + from + `"`
panic(msg)
}
denoms, amounts := amt.expandNative()
bankerSendCoins(uint8(b.bt), string(from), string(to), denoms, amounts)
}
Expand Down
17 changes: 0 additions & 17 deletions gnovm/stdlibs/std/banker.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,6 @@ func X_bankerSendCoins(m *gno.Machine, bt uint8, fromS, toS string, denoms []str
amt := CompactCoins(denoms, amounts)
from, to := crypto.Bech32Address(fromS), crypto.Bech32Address(toS)

pkgAddr := ctx.OrigPkgAddr
if m.Realm != nil {
pkgPath := m.Realm.Path
pkgAddr = gno.DerivePkgAddr(pkgPath).Bech32()
}

if bt == btOrigSend || bt == btRealmSend {
if from != pkgAddr {
m.Panic(typedString(
fmt.Sprintf(
"can only send from the realm package address %q, but got %q",
pkgAddr, from),
))
return
}
}

switch bt {
case btOrigSend:
// indirection allows us to "commit" in a second phase
Expand Down

0 comments on commit 876eaf9

Please sign in to comment.