gui.go 13.6 KB
Newer Older
F
Felix Lange 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
// MA 02110-1301  USA

O
obscuren 已提交
18
package main
O
obscuren 已提交
19

O
obscuren 已提交
20 21
import "C"

O
obscuren 已提交
22
import (
O
obscuren 已提交
23
	"bytes"
O
obscuren 已提交
24
	"encoding/json"
O
obscuren 已提交
25
	"fmt"
O
obscuren 已提交
26
	"math/big"
O
obscuren 已提交
27
	"path"
O
obscuren 已提交
28
	"runtime"
O
obscuren 已提交
29 30 31
	"strconv"
	"strings"
	"time"
O
Removed  
obscuren 已提交
32

O
obscuren 已提交
33 34
	"github.com/ethereum/go-ethereum/core"
	"github.com/ethereum/go-ethereum/core/types"
35
	"github.com/ethereum/go-ethereum/eth"
36 37
	"github.com/ethereum/go-ethereum/ethdb"
	"github.com/ethereum/go-ethereum/ethutil"
O
obscuren 已提交
38
	"github.com/ethereum/go-ethereum/logger"
O
obscuren 已提交
39
	"github.com/ethereum/go-ethereum/miner"
40
	"github.com/ethereum/go-ethereum/p2p"
41
	"github.com/ethereum/go-ethereum/ui/qt/qwhisper"
O
obscuren 已提交
42
	"github.com/ethereum/go-ethereum/xeth"
O
obscuren 已提交
43
	"gopkg.in/qml.v1"
O
obscuren 已提交
44 45
)

O
obscuren 已提交
46
var guilogger = logger.NewLogger("GUI")
47

O
obscuren 已提交
48
type Gui struct {
49 50 51
	// The main application window
	win *qml.Window
	// QML Engine
O
obscuren 已提交
52 53
	engine    *qml.Engine
	component *qml.Common
54
	qmlDone   bool
55 56
	// The ethereum interface
	eth *eth.Ethereum
O
obscuren 已提交
57

58
	// The public Ethereum library
59 60
	uiLib   *UiLib
	whisper *qwhisper.Whisper
O
obscuren 已提交
61 62 63

	txDb *ethdb.LDBDatabase

O
obscuren 已提交
64
	logLevel logger.LogLevel
Z
go fmt  
zelig 已提交
65
	open     bool
Z
zelig 已提交
66

O
obscuren 已提交
67
	pipe *xeth.JSXEth
O
obscuren 已提交
68

Z
zelig 已提交
69
	Session        string
70
	clientIdentity *p2p.SimpleClientIdentity
Z
zelig 已提交
71
	config         *ethutil.ConfigManager
M
Maran 已提交
72

O
obscuren 已提交
73 74
	plugins map[string]plugin

O
obscuren 已提交
75
	miner  *miner.Miner
O
obscuren 已提交
76
	stdLog logger.LogSystem
O
obscuren 已提交
77 78
}

79
// Create GUI, but doesn't start it
80
func NewWindow(ethereum *eth.Ethereum, config *ethutil.ConfigManager, clientIdentity *p2p.SimpleClientIdentity, session string, logLevel int) *Gui {
O
obscuren 已提交
81 82 83 84
	db, err := ethdb.NewLDBDatabase("tx_database")
	if err != nil {
		panic(err)
	}
O
obscuren 已提交
85

O
obscuren 已提交
86
	pipe := xeth.NewJSXEth(ethereum)
O
obscuren 已提交
87
	gui := &Gui{eth: ethereum, txDb: db, pipe: pipe, logLevel: logger.LogLevel(logLevel), Session: session, open: false, clientIdentity: clientIdentity, config: config, plugins: make(map[string]plugin)}
O
obscuren 已提交
88
	data, _ := ethutil.ReadAllFile(path.Join(ethutil.Config.ExecPath, "plugins.json"))
O
obscuren 已提交
89 90 91
	json.Unmarshal([]byte(data), &gui.plugins)

	return gui
O
obscuren 已提交
92 93
}

O
Cleanup  
obscuren 已提交
94 95
func (gui *Gui) Start(assetPath string) {
	defer gui.txDb.Close()
O
obscuren 已提交
96

O
obscuren 已提交
97 98
	guilogger.Infoln("Starting GUI")

99 100
	// Register ethereum functions
	qml.RegisterTypes("Ethereum", 1, 0, []qml.TypeSpec{{
O
obscuren 已提交
101
		Init: func(p *xeth.JSBlock, obj qml.Object) { p.Number = 0; p.Hash = "" },
O
obscuren 已提交
102
	}, {
O
obscuren 已提交
103
		Init: func(p *xeth.JSTransaction, obj qml.Object) { p.Value = ""; p.Hash = ""; p.Address = "" },
104
	}, {
O
obscuren 已提交
105
		Init: func(p *xeth.KeyVal, obj qml.Object) { p.Key = ""; p.Value = "" },
O
obscuren 已提交
106
	}})
107
	// Create a new QML engine
O
Cleanup  
obscuren 已提交
108 109
	gui.engine = qml.NewEngine()
	context := gui.engine.Context()
110
	gui.uiLib = NewUiLib(gui.engine, gui.eth, assetPath)
111
	gui.whisper = qwhisper.New(gui.eth.Whisper())
112 113

	// Expose the eth library and the ui library to QML
114 115
	context.SetVar("gui", gui)
	context.SetVar("eth", gui.uiLib)
116
	context.SetVar("shh", gui.whisper)
J
Jarrad Hope 已提交
117

118
	// Load the main QML interface
119
	data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
O
obscuren 已提交
120 121

	var win *qml.Window
122
	var err error
Z
zelig 已提交
123
	var addlog = false
O
obscuren 已提交
124 125
	if len(data) == 0 {
		win, err = gui.showKeyImport(context)
126
	} else {
O
obscuren 已提交
127
		win, err = gui.showWallet(context)
Z
zelig 已提交
128
		addlog = true
129
	}
O
obscuren 已提交
130
	if err != nil {
O
obscuren 已提交
131
		guilogger.Errorln("asset not found: you can set an alternative asset path on the command line using option 'asset_path'", err)
132

O
obscuren 已提交
133 134 135
		panic(err)
	}

Z
zelig 已提交
136
	gui.open = true
137
	win.Show()
O
obscuren 已提交
138

O
obscuren 已提交
139
	// only add the gui guilogger after window is shown otherwise slider wont be shown
Z
zelig 已提交
140
	if addlog {
O
obscuren 已提交
141
		logger.AddLogSystem(gui)
Z
zelig 已提交
142
	}
O
obscuren 已提交
143
	win.Wait()
O
obscuren 已提交
144

O
obscuren 已提交
145 146
	// need to silence gui guilogger after window closed otherwise logsystem hangs (but do not save loglevel)
	gui.logLevel = logger.Silence
Z
zelig 已提交
147 148 149 150 151
	gui.open = false
}

func (gui *Gui) Stop() {
	if gui.open {
O
obscuren 已提交
152
		gui.logLevel = logger.Silence
Z
zelig 已提交
153 154 155
		gui.open = false
		gui.win.Hide()
	}
156

157
	gui.uiLib.jsEngine.Stop()
158

O
obscuren 已提交
159
	guilogger.Infoln("Stopped")
O
obscuren 已提交
160
}
O
obscuren 已提交
161

O
obscuren 已提交
162
func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
O
obscuren 已提交
163
	component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/main.qml"))
O
obscuren 已提交
164 165
	if err != nil {
		return nil, err
166
	}
O
obscuren 已提交
167

168
	gui.win = gui.createWindow(component)
O
obscuren 已提交
169

Z
zelig 已提交
170
	gui.update()
O
obscuren 已提交
171

172 173 174 175 176 177
	return gui.win, nil
}

// The done handler will be called by QML when all views have been loaded
func (gui *Gui) Done() {
	gui.qmlDone = true
O
obscuren 已提交
178 179
}

O
obscuren 已提交
180 181 182
func (gui *Gui) ImportKey(filePath string) {
}

O
obscuren 已提交
183
func (gui *Gui) showKeyImport(context *qml.Context) (*qml.Window, error) {
Z
zelig 已提交
184
	context.SetVar("lib", gui)
O
obscuren 已提交
185 186 187 188 189 190 191 192 193 194 195 196 197 198
	component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/first_run.qml"))
	if err != nil {
		return nil, err
	}
	return gui.createWindow(component), nil
}

func (gui *Gui) createWindow(comp qml.Object) *qml.Window {
	win := comp.CreateWindow(nil)

	gui.win = win
	gui.uiLib.win = win

	return gui.win
O
obscuren 已提交
199
}
Z
zelig 已提交
200 201 202 203

func (gui *Gui) ImportAndSetPrivKey(secret string) bool {
	err := gui.eth.KeyManager().InitFromString(gui.Session, 0, secret)
	if err != nil {
O
obscuren 已提交
204
		guilogger.Errorln("unable to import: ", err)
Z
zelig 已提交
205 206
		return false
	}
O
obscuren 已提交
207
	guilogger.Errorln("successfully imported: ", err)
Z
zelig 已提交
208 209 210 211 212 213
	return true
}

func (gui *Gui) CreateAndSetPrivKey() (string, string, string, string) {
	err := gui.eth.KeyManager().Init(gui.Session, 0, true)
	if err != nil {
O
obscuren 已提交
214
		guilogger.Errorln("unable to create key: ", err)
Z
zelig 已提交
215 216 217 218 219
		return "", "", "", ""
	}
	return gui.eth.KeyManager().KeyPair().AsStrings()
}

O
obscuren 已提交
220
func (gui *Gui) setInitialChain(ancientBlocks bool) {
O
obscuren 已提交
221
	sBlk := gui.eth.ChainManager().LastBlockHash()
O
obscuren 已提交
222 223
	blk := gui.eth.ChainManager().GetBlock(sBlk)
	for ; blk != nil; blk = gui.eth.ChainManager().GetBlock(sBlk) {
M
Maran 已提交
224
		sBlk = blk.PrevHash
225

M
Maran 已提交
226
		gui.processBlock(blk, true)
227 228 229
	}
}

O
obscuren 已提交
230
func (gui *Gui) loadAddressBook() {
231
	view := gui.getObjectByName("infoView")
O
obscuren 已提交
232
	nameReg := gui.pipe.World().Config().Get("NameReg")
O
obscuren 已提交
233
	if nameReg != nil {
O
obscuren 已提交
234
		nameReg.EachStorage(func(name string, value *ethutil.Value) {
235
			if name[0] != 0 {
O
obscuren 已提交
236
				value.Decode()
237 238

				view.Call("addAddress", struct{ Name, Address string }{name, ethutil.Bytes2Hex(value.Bytes())})
239
			}
240 241
		})
	}
O
obscuren 已提交
242 243
}

244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
func (self *Gui) loadMergedMiningOptions() {
	view := self.getObjectByName("mergedMiningModel")

	nameReg := self.pipe.World().Config().Get("MergeMining")
	if nameReg != nil {
		i := 0
		nameReg.EachStorage(func(name string, value *ethutil.Value) {
			if name[0] != 0 {
				value.Decode()

				view.Call("addMergedMiningOption", struct {
					Checked       bool
					Name, Address string
					Id, ItemId    int
				}{false, name, ethutil.Bytes2Hex(value.Bytes()), 0, i})

				i++
			}
		})
	}
}

266
func (gui *Gui) insertTransaction(window string, tx *types.Transaction) {
O
obscuren 已提交
267
	pipe := xeth.New(gui.eth)
O
obscuren 已提交
268
	nameReg := pipe.World().Config().Get("NameReg")
Z
zelig 已提交
269
	addr := gui.address()
O
obscuren 已提交
270

O
obscuren 已提交
271
	var inout string
272
	if bytes.Compare(tx.From(), addr) == 0 {
O
obscuren 已提交
273 274 275 276 277 278
		inout = "send"
	} else {
		inout = "recv"
	}

	var (
O
obscuren 已提交
279
		ptx  = xeth.NewJSTx(tx, pipe.World().State())
280 281
		send = nameReg.Storage(tx.From())
		rec  = nameReg.Storage(tx.To())
O
obscuren 已提交
282 283 284
		s, r string
	)

O
obscuren 已提交
285
	if core.MessageCreatesContract(tx) {
286
		rec = nameReg.Storage(core.AddressFromMessage(tx))
O
obscuren 已提交
287 288 289 290 291
	}

	if send.Len() != 0 {
		s = strings.Trim(send.Str(), "\x00")
	} else {
292
		s = ethutil.Bytes2Hex(tx.From())
O
obscuren 已提交
293 294 295 296
	}
	if rec.Len() != 0 {
		r = strings.Trim(rec.Str(), "\x00")
	} else {
O
obscuren 已提交
297
		if core.MessageCreatesContract(tx) {
298
			r = ethutil.Bytes2Hex(core.AddressFromMessage(tx))
O
obscuren 已提交
299
		} else {
300
			r = ethutil.Bytes2Hex(tx.To())
O
obscuren 已提交
301
		}
O
obscuren 已提交
302 303 304 305
	}
	ptx.Sender = s
	ptx.Address = r

306
	if window == "post" {
O
obscuren 已提交
307
		//gui.getObjectByName("transactionView").Call("addTx", ptx, inout)
308 309 310
	} else {
		gui.getObjectByName("pendingTxView").Call("addTx", ptx, inout)
	}
O
obscuren 已提交
311
}
O
obscuren 已提交
312

O
obscuren 已提交
313
func (gui *Gui) readPreviousTransactions() {
O
obscuren 已提交
314
	it := gui.txDb.NewIterator()
O
obscuren 已提交
315
	for it.Next() {
316
		tx := types.NewTransactionFromBytes(it.Value())
O
obscuren 已提交
317 318

		gui.insertTransaction("post", tx)
O
obscuren 已提交
319

O
obscuren 已提交
320 321 322 323
	}
	it.Release()
}

324
func (gui *Gui) processBlock(block *types.Block, initial bool) {
O
obscuren 已提交
325
	name := strings.Trim(gui.pipe.World().Config().Get("NameReg").Storage(block.Coinbase).Str(), "\x00")
O
obscuren 已提交
326
	b := xeth.NewJSBlock(block)
327 328
	b.Name = name

329
	gui.getObjectByName("chainView").Call("addBlock", b, initial)
O
obscuren 已提交
330 331
}

332 333 334 335
func (gui *Gui) setWalletValue(amount, unconfirmedFunds *big.Int) {
	var str string
	if unconfirmedFunds != nil {
		pos := "+"
O
obscuren 已提交
336
		if unconfirmedFunds.Cmp(big.NewInt(0)) < 0 {
337 338 339 340 341 342 343 344 345 346 347
			pos = "-"
		}
		val := ethutil.CurrencyToString(new(big.Int).Abs(ethutil.BigCopy(unconfirmedFunds)))
		str = fmt.Sprintf("%v (%s %v)", ethutil.CurrencyToString(amount), pos, val)
	} else {
		str = fmt.Sprintf("%v", ethutil.CurrencyToString(amount))
	}

	gui.win.Root().Call("setWalletValue", str)
}

O
obscuren 已提交
348 349 350 351
func (self *Gui) getObjectByName(objectName string) qml.Object {
	return self.win.Root().ObjectByName(objectName)
}

O
obscuren 已提交
352
// Simple go routine function that updates the list of peers in the GUI
O
Cleanup  
obscuren 已提交
353
func (gui *Gui) update() {
354 355
	// We have to wait for qml to be done loading all the windows.
	for !gui.qmlDone {
O
obscuren 已提交
356
		time.Sleep(300 * time.Millisecond)
357 358 359
	}

	go func() {
O
obscuren 已提交
360
		go gui.setInitialChain(false)
361
		gui.loadAddressBook()
362
		gui.loadMergedMiningOptions()
363 364
		gui.setPeerInfo()
	}()
365

366 367
	gui.whisper.SetView(gui.win.Root().ObjectByName("whisperView"))

O
obscuren 已提交
368
	for _, plugin := range gui.plugins {
O
obscuren 已提交
369
		guilogger.Infoln("Loading plugin ", plugin.Name)
O
obscuren 已提交
370

O
obscuren 已提交
371 372 373
		gui.win.Root().Call("addPlugin", plugin.Path, "")
	}

O
obscuren 已提交
374
	peerUpdateTicker := time.NewTicker(5 * time.Second)
O
obscuren 已提交
375
	generalUpdateTicker := time.NewTicker(500 * time.Millisecond)
O
obscuren 已提交
376
	statsUpdateTicker := time.NewTicker(5 * time.Second)
M
Maran 已提交
377

O
obscuren 已提交
378
	state := gui.eth.ChainManager().TransState()
O
obscuren 已提交
379

O
obscuren 已提交
380
	gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.address()).Balance())))
O
obscuren 已提交
381 382

	lastBlockLabel := gui.getObjectByName("lastBlockLabel")
O
obscuren 已提交
383
	miningLabel := gui.getObjectByName("miningLabel")
O
obscuren 已提交
384

F
Felix Lange 已提交
385
	events := gui.eth.EventMux().Subscribe(
386
		//eth.PeerListEvent{},
O
obscuren 已提交
387 388 389
		core.NewBlockEvent{},
		core.TxPreEvent{},
		core.TxPostEvent{},
F
Felix Lange 已提交
390 391
	)

Z
zelig 已提交
392
	go func() {
F
Felix Lange 已提交
393
		defer events.Unsubscribe()
Z
zelig 已提交
394 395
		for {
			select {
F
Felix Lange 已提交
396 397 398
			case ev, isopen := <-events.Chan():
				if !isopen {
					return
Z
zelig 已提交
399
				}
F
Felix Lange 已提交
400
				switch ev := ev.(type) {
O
obscuren 已提交
401
				case core.NewBlockEvent:
F
Felix Lange 已提交
402 403
					gui.processBlock(ev.Block, false)
					if bytes.Compare(ev.Block.Coinbase, gui.address()) == 0 {
O
obscuren 已提交
404
						gui.setWalletValue(gui.eth.ChainManager().State().GetBalance(gui.address()), nil)
F
Felix Lange 已提交
405
					}
O
obscuren 已提交
406

O
obscuren 已提交
407
				case core.TxPreEvent:
F
Felix Lange 已提交
408
					tx := ev.Tx
O
Cleanup  
obscuren 已提交
409

O
obscuren 已提交
410 411
					tstate := gui.eth.ChainManager().TransState()
					cstate := gui.eth.ChainManager().State()
412

413 414 415 416 417
					taccount := tstate.GetAccount(gui.address())
					caccount := cstate.GetAccount(gui.address())
					unconfirmedFunds := new(big.Int).Sub(taccount.Balance(), caccount.Balance())

					gui.setWalletValue(taccount.Balance(), unconfirmedFunds)
418
					gui.insertTransaction("pre", tx)
O
obscuren 已提交
419

O
obscuren 已提交
420
				case core.TxPostEvent:
421 422
					tx := ev.Tx
					object := state.GetAccount(gui.address())
O
obscuren 已提交
423

424
					if bytes.Compare(tx.From(), gui.address()) == 0 {
425
						object.SubAmount(tx.Value())
O
obscuren 已提交
426

427
						gui.txDb.Put(tx.Hash(), tx.RlpEncode())
428 429
					} else if bytes.Compare(tx.To(), gui.address()) == 0 {
						object.AddAmount(tx.Value())
F
Felix Lange 已提交
430

431
						gui.txDb.Put(tx.Hash(), tx.RlpEncode())
Z
zelig 已提交
432
					}
433

434 435
					gui.setWalletValue(object.Balance(), nil)
					state.UpdateStateObject(object)
Z
zelig 已提交
436
				}
Z
zelig 已提交
437 438

			case <-peerUpdateTicker.C:
Z
zelig 已提交
439
				gui.setPeerInfo()
Z
zelig 已提交
440
			case <-generalUpdateTicker.C:
O
obscuren 已提交
441
				statusText := "#" + gui.eth.ChainManager().CurrentBlock().Number.String()
O
obscuren 已提交
442
				lastBlockLabel.Set("text", statusText)
443
				miningLabel.Set("text", "Mining @ "+strconv.FormatInt(gui.uiLib.miner.GetPow().GetHashrate(), 10)+"Khash")
O
obscuren 已提交
444

445 446 447
				/*
					blockLength := gui.eth.BlockPool().BlocksProcessed
					chainLength := gui.eth.BlockPool().ChainLength
O
obscuren 已提交
448

449 450 451 452 453 454 455 456
					var (
						pct      float64 = 1.0 / float64(chainLength) * float64(blockLength)
						dlWidget         = gui.win.Root().ObjectByName("downloadIndicator")
						dlLabel          = gui.win.Root().ObjectByName("downloadLabel")
					)
					dlWidget.Set("value", pct)
					dlLabel.Set("text", fmt.Sprintf("%d / %d", blockLength, chainLength))
				*/
O
obscuren 已提交
457

O
obscuren 已提交
458 459
			case <-statsUpdateTicker.C:
				gui.setStatsPane()
O
obscuren 已提交
460 461
			}
		}
Z
zelig 已提交
462
	}()
O
obscuren 已提交
463 464
}

O
obscuren 已提交
465 466 467 468 469
func (gui *Gui) setStatsPane() {
	var memStats runtime.MemStats
	runtime.ReadMemStats(&memStats)

	statsPane := gui.getObjectByName("statsPane")
O
obscuren 已提交
470
	statsPane.Set("text", fmt.Sprintf(`###### Mist %s (%s) #######
O
obscuren 已提交
471 472

eth %d (p2p = %d)
O
obscuren 已提交
473 474 475 476 477 478 479 480 481 482

CPU:        # %d
Goroutines: # %d
CGoCalls:   # %d

Alloc:      %d
Heap Alloc: %d

CGNext:     %x
NumGC:      %d
O
obscuren 已提交
483
`, Version, runtime.Version(),
484
		eth.ProtocolVersion, 2,
O
obscuren 已提交
485
		runtime.NumCPU, runtime.NumGoroutine(), runtime.NumCgoCall(),
O
obscuren 已提交
486 487 488 489 490
		memStats.Alloc, memStats.HeapAlloc,
		memStats.NextGC, memStats.NumGC,
	))
}

O
obscuren 已提交
491 492
func (gui *Gui) setPeerInfo() {
	gui.win.Root().Call("setPeers", fmt.Sprintf("%d / %d", gui.eth.PeerCount(), gui.eth.MaxPeers))
M
Maran 已提交
493
	gui.win.Root().Call("resetPeers")
O
obscuren 已提交
494
	for _, peer := range gui.pipe.Peers() {
M
Maran 已提交
495 496
		gui.win.Root().Call("addPeer", peer)
	}
O
obscuren 已提交
497 498
}

Z
zelig 已提交
499 500 501 502 503 504 505
func (gui *Gui) privateKey() string {
	return ethutil.Bytes2Hex(gui.eth.KeyManager().PrivateKey())
}

func (gui *Gui) address() []byte {
	return gui.eth.KeyManager().Address()
}
O
obscuren 已提交
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537

/*
func LoadExtension(path string) (uintptr, error) {
	lib, err := ffi.NewLibrary(path)
	if err != nil {
		return 0, err
	}

	so, err := lib.Fct("sharedObject", ffi.Pointer, nil)
	if err != nil {
		return 0, err
	}

	ptr := so()

		err = lib.Close()
		if err != nil {
			return 0, err
		}

	return ptr.Interface().(uintptr), nil
}
*/
/*
	vec, errr := LoadExtension("/Users/jeffrey/Desktop/build-libqmltest-Desktop_Qt_5_2_1_clang_64bit-Debug/liblibqmltest_debug.dylib")
	fmt.Printf("Fetched vec with addr: %#x\n", vec)
	if errr != nil {
		fmt.Println(errr)
	} else {
		context.SetVar("vec", (unsafe.Pointer)(vec))
	}
*/