Skip to content

Commit

Permalink
test wallet restore
Browse files Browse the repository at this point in the history
  • Loading branch information
elnosh committed Jun 24, 2024
1 parent d7661ac commit edb5b03
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 14 deletions.
13 changes: 8 additions & 5 deletions cmd/nutw/nutw.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,12 +334,15 @@ var restoreCmd = &cli.Command{
}

func restore(ctx *cli.Context) error {
args := ctx.Args()
if args.Len() < 1 {
printErr(errors.New("specify mnemonic"))
}
mnemonic := args.First()
config := walletConfig()
fmt.Printf("enter mnemonic: ")

reader := bufio.NewReader(os.Stdin)
mnemonic, err := reader.ReadString('\n')
if err != nil {
log.Fatal("error reading input, please try again")
}
mnemonic = mnemonic[:len(mnemonic)-1]

proofs, err := wallet.Restore(config.WalletPath, mnemonic, []string{config.CurrentMintURL})
if err != nil {
Expand Down
52 changes: 52 additions & 0 deletions testutils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"github.com/elnosh/gonuts/mint"
"github.com/elnosh/gonuts/wallet"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
)

const (
Expand Down Expand Up @@ -361,3 +363,53 @@ func GetValidProofsForAmount(amount uint64, mint *mint.Mint, payer *btcdocker.Ln

return proofs, nil
}

type NutshellMintContainer struct {
testcontainers.Container
Host string
}

func CreateNutshellMintContainer(ctx context.Context) (*NutshellMintContainer, error) {
req := testcontainers.ContainerRequest{
Image: "cashubtc/nutshell:0.15.3",
ExposedPorts: []string{"3338"},
Cmd: []string{
"poetry",
"run",
"mint",
},
Env: map[string]string{
"MINT_LISTEN_HOST": "0.0.0.0",
"MINT_LISTEN_PORT": "3338",
"MINT_BACKEND_BOLT11_SAT": "FakeWallet",
"MINT_PRIVATE_KEY": "secretkey",
},
WaitingFor: wait.ForListeningPort("3338"),
}

container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
if err != nil {
return nil, err
}

ip, err := container.Host(ctx)
if err != nil {
return nil, err
}

mappedPort, err := container.MappedPort(ctx, "3338")
if err != nil {
return nil, err
}

nutshellHost := "http:https://" + ip + ":" + mappedPort.Port()
nutshellContainer := &NutshellMintContainer{
Container: container,
Host: nutshellHost,
}

return nutshellContainer, nil
}
16 changes: 7 additions & 9 deletions wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -955,17 +955,17 @@ func Restore(walletPath, mnemonic string, mintsToRestore []string) (cashu.Proofs
return nil, errors.New("wallet already exists")
}

// check mnemonic is valid
if !bip39.IsMnemonicValid(mnemonic) {
return nil, errors.New("invalid mnemonic")
}

// create wallet db
db, err := InitStorage(walletPath)
if err != nil {
return nil, fmt.Errorf("error restoring wallet: %v", err)
}

// check mnemonic is valid
if !bip39.IsMnemonicValid(mnemonic) {
return nil, errors.New("invalid mnemonic")
}

seed := bip39.NewSeed(mnemonic, "")
// get master key from seed
masterKey, err := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)
Expand Down Expand Up @@ -1035,12 +1035,11 @@ func Restore(walletPath, mnemonic string, mintsToRestore []string) (cashu.Proofs
// stop when it reaches 3 consecutive empty batches
emptyBatches := 0
for emptyBatches < 3 {

blindedMessages := make(cashu.BlindedMessages, 100)
rs := make([]*secp256k1.PrivateKey, 100)
secrets := make([]string, 100)

// loop and create batch of 100 blinded messages here
// create batch of 100 blinded messages
for i := 0; i < 100; i++ {
B_, secret, r, err := blindMessage(keysetDerivationPath, counter)
if err != nil {
Expand All @@ -1054,7 +1053,7 @@ func Restore(walletPath, mnemonic string, mintsToRestore []string) (cashu.Proofs
counter++
}

// call signature restore endpoint. if response has signatures, unblind them and check proof states
// if response has signatures, unblind them and check proof states
restoreRequest := nut09.PostRestoreRequest{Outputs: blindedMessages}
restoreResponse, err := PostRestore(mint, restoreRequest)
if err != nil {
Expand Down Expand Up @@ -1123,7 +1122,6 @@ func Restore(walletPath, mnemonic string, mintsToRestore []string) (cashu.Proofs
}
emptyBatches = 0
}

}
}

Expand Down
75 changes: 75 additions & 0 deletions wallet/wallet_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -376,3 +376,78 @@ func TestWalletBalance(t *testing.T) {
t.Fatalf("expected balance of '%v' but got '%v' instead", balanceBeforeMelt, balanceTestWallet.GetBalance())
}
}

func TestWalletRestore(t *testing.T) {
nutshellMint, err := testutils.CreateNutshellMintContainer(ctx)
if err != nil {
t.Fatalf("error starting nutshell mint: %v", err)
}
defer nutshellMint.Terminate(ctx)

mintURL := nutshellMint.Host

testWalletPath := filepath.Join(".", "/testrestorewallet")
testWallet, err := testutils.CreateTestWallet(testWalletPath, mintURL)
if err != nil {
t.Fatal(err)
}

testWalletPath2 := filepath.Join(".", "/testrestorewallet2")
testWallet2, err := testutils.CreateTestWallet(testWalletPath2, mintURL)
if err != nil {
t.Fatal(err)
}
defer func() {
os.RemoveAll(testWalletPath2)
}()

var mintAmount uint64 = 20000
mintRequest, err := testWallet.RequestMint(mintAmount)
if err != nil {
t.Fatalf("unexpected error in mint request: %v", err)
}
_, err = testWallet.MintTokens(mintRequest.Quote)
if err != nil {
t.Fatalf("unexpected error in mint tokens: %v", err)
}

var sendAmount1 uint64 = 5000
token, err := testWallet.Send(sendAmount1, mintURL)
if err != nil {
t.Fatalf("unexpected error in send: %v", err)
}

_, err = testWallet2.Receive(*token, false)
if err != nil {
t.Fatalf("got unexpected error in receive: %v", err)
}

var sendAmount2 uint64 = 1000
token, err = testWallet.Send(sendAmount2, mintURL)
if err != nil {
t.Fatalf("unexpected error in send: %v", err)
}

_, err = testWallet2.Receive(*token, false)
if err != nil {
t.Fatalf("got unexpected error in receive: %v", err)
}

mnemonic := testWallet.Mnemonic()

// delete wallet db to restore
os.RemoveAll(filepath.Join(testWalletPath, "wallet.db"))

proofs, err := wallet.Restore(testWalletPath, mnemonic, []string{mintURL})
if err != nil {
t.Fatalf("error restoring wallet: %v\n", err)
}

expectedAmount := mintAmount - sendAmount1 - sendAmount2
if proofs.Amount() != expectedAmount {
t.Fatalf("restored proofs amount '%v' does not match to expected amount '%v'", proofs.Amount(), expectedAmount)
}
defer func() {
os.RemoveAll(testWalletPath)
}()
}

0 comments on commit edb5b03

Please sign in to comment.