Rust: Borsh Serialize
Study how to use Borsh Serialize. When we write vanila Solana program, we need to serialize and deserialize accounts’ data by ourselves.
1 | // Cargo.toml |
1 | // main.rs |
Run the code:
1 | $ cargo run |
Study how to use Borsh Serialize. When we write vanila Solana program, we need to serialize and deserialize accounts’ data by ourselves.
1 | // Cargo.toml |
1 | // main.rs |
Run the code:
1 | $ cargo run |
1 | // rest.js |
run the code:
1 | $ node rest.js |
Problem: Implement strStr()
Given two strings needle and haystack, return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack. If needle is empty, return 0.
strategies:
find
method1 | impl Solution { |
1 | impl Solution { |
1 | const MAGIC_NUM: u64 = 31; // can be any number but should not too big |
1 | impl Solution { |
1 | let str = String::from("好"); |
Since the len()
returns the length of bytes not characters, we need to change our code if unicode strings given.
1 | impl Solution { |
find
looks easier.Given a inorder-traversal result and a preorder-traversal result of a tree, Figure out the tree structure.
For example:
What is the structure of this tree? Can we build a tree based on these two clues?
The first element of preorder-traversal must be the Root of a tree. On the other hand, we can determine left and right from inorder-traversal after we get the root. As the result, we can again get inorder and preorder result of left-sub-tree and right-sub-tree, then both left and right redo above process until they get no or only one element.
Overview the tree for now
So we can expect we can get the whole tree if we repeat the process.
1 | pub struct Node { |
Problem: Koko Eating Bananas
Let’s draw some pictures to understand this quesiton. If there are 4 piles of bananas like below, the given array would be [3, 2, 4, 1]
.
Then if Koko can eat 3 bananas per hour, it will takes her 5 hours to eat all the bananas like blow.
Now, if the limit hours h
is 5 then 3 bananas per hour satisfies. However, if h
, for example, is 3, then Koko need to SPEEDS UP to finish all the bananas. On the other hand, if h
is 10 which means we still have time right? So Koko should SLOW DOWN to certain speed to make herself chill but still can finish all the bananas in time.
So what is the best eating speed is the question!
Which means we are trying to find the best from 1
~ piles.max()
. Searching a value from a sorted array… maybe binary search is a soslution.
1 | use std::cmp::Ordering; |
The core concept is to find the target from a sorted array which is quite suitable to use binary serach I think.
Here are my instructions:
mid
mid
with the target. there will be 3 branches:target
< mid
: continue to find the target from the LEFT side of the mid
target
> mid
: continue to find the target from the RIGHT side of the mid
target
= mid
: In this case, [index_of_mid, index_of_mid]
will be our base answer so keep it. Then based on this answer, we need to go further to the both left and right to seek if there is other elements match to the search target.For example, if the given array is [1, 2, 3, 4, 4, 4, 4, 6, 9]
, and the search target is 4
.
Then we are trying to get this green range.
When we go through the instructions, we will get the middle element, and hit the c case.
Then base on this position, we seek towar left and right to get the final range.
So the answer should be [3, 6]
1 | impl Solution { |
1 | use std::cmp::Ordering; // Don't forget to import this |
Improvements
Solution
structLearned
cmp
& match
Solution::bst_search_index_inner
Just a quick note for these two functions I learned today.
checked_sub
is used to check if the abstraction of an integer overflows. For example:
1 | let mut num_u32: u32 = 0; |
To prevent it, we can use the combo of checked_sub
and unwrap_or
. checked_sub
will return Option<self>
which means if there is no overflow occurs, we get Some(substraction_result)
, else we will get None
. unwarp_or
can then give the result a default value if we get None
or just unwrap Some(substraction_result)
to return substraction_result
. Let’s look at the code.
1 | let mut num_i32 = i32::MIN + 1; // -2147483648 + 1 |
That’s it for today!
希望能以最直觀的方式解釋 Solana 鏈上的代幣,也就是 Token。
注意!這邊特指是 Solana 的,因為會跟乙太坊的代幣細節上有諸多不同,有興趣可以再去研究一下兩者的差別。
本文適合那些看了官方文件還是霧嗄嗄 (bū-sà-sà) 的人,像我自己。
以外匯為例,假設阿蟹今天要在銀行存美金、日幣、和歐元,那他勢必要開三個對應的帳戶。美金帳戶只能存美金、日幣帳戶只能存日幣、歐元帳戶只能存歐元。
而 Solana 的代幣其實也是一樣的規則,當我們想要持有某一代幣 (token) 時,我們就必須先創建那個代幣的帳戶 (associated account),然後才能把代幣轉過去。
所以想要持有幾種代幣,就需要幾個代幣帳戶。
而除了持有各種幣,我們也可以在 Solana 上發行自己的代幣。
以美金做比喻的話,「發行」就是美國央行跟大家宣布他要發行一種貨幣,代號為 USD;在實際鑄造 USD 前,USD 的總發行量會為 0。
接著美國央行可以決定要鑄造多少 USD,而其他人都不可以鑄造 USD。美國央行鑄造出來的 USD ,可以指定給任意對象:可以給央行自己的 USD 帳戶,也可以給到任意對象的 USD 帳戶。
所以鑄幣權的概念其實滿直觀的:只有該代幣「發行人」有權鑄造 (mint) 該代幣,其他人無法鑄造,但可以被指定爲鑄造出來的代幣的「接收者」 (recipient),前提是要擁有該代幣的帳戶。
其實在 Solana 鏈上,NFT 跟我們一開始談的代幣本質上沒有區別,都是 token。
在 Solana 上發行代幣時,我們可以設定最小單位,預設為 0.000000001;而總量可以有上限,也可以無限。而 NFT 只是最小單位為 1,且發行總量為 1 的代幣!
NFT on Solana:
而且一樣的,要存一個 NFT,我們也需要開一個對應的帳戶去存他。
到上面,其實就已經把 Solana 代幣的概念講完了。
沒錯,就是這麼簡單~
以下是比較技術的部分。我們會實際操作 CLI 實作代幣的發行。
英文不錯的可以直接照著官方文件操作。
1 | $ spl-token create-token |
執行結果:
1 | $ spl-token create-token |
這樣就發行代幣了!而該代幣的代號為:4o4wYDr7mQGFFawdhdaHCz5CTTeZtsdw4aVdyCApXZHd
。每次代號都不同,所以你自己實作時會產生你自己代幣的代號。以下我們都用 <代幣 ID>
表示。
發行完後,我們可以查看該代幣總量
1 | $ spl-token supply <代幣 ID> |
執行結果:
1 | $ spl-token supply 4o4wYDr7mQGFFawdhdaHCz5CTTeZtsdw4aVdyCApXZHd |
目前代幣總量應為 0,因為我們還沒鑄造任何代幣。
開一個代幣帳戶,此帳戶「只能」存該代幣。
1 | $ spl-token create-account <代幣 ID> |
執行結果:
1 | $ spl-token create-account 4o4wYDr7mQGFFawdhdaHCz5CTTeZtsdw4aVdyCApXZHd |
所以我們的代幣帳號為 9Vz65o3NNNJvhPnheCr6MfFx7HUwxnZt4JhLSXEmmfqz
,他是專門用來存代幣 4o4wYDr7mQGFFawdhdaHCz5CTTeZtsdw4aVdyCApXZHd
的。
1 | $ spl-token mint <代幣 ID> <欲鑄造數量> <接收的代幣帳戶> |
執行結果:
1 | $ spl-token mint 4o4wYDr7mQGFFawdhdaHCz5CTTeZtsdw4aVdyCApXZHd 100 |
如果 <接收的代幣帳戶>
沒給定,預設會是自己的代幣帳戶;如果之前沒有創建代幣帳戶,這次的鑄造就會失敗。
我們成功的轉了 100 的 4o4wYDr7mQGFFawdhdaHCz5CTTeZtsdw4aVdyCApXZHd
代幣到我 9Vz65o3NNNJvhPnheCr6MfFx7HUwxnZt4JhLSXEmmfqz
的帳戶了。
查看我們的帳戶:
1 | $ spl-token accounts |
執行結果:
1 | $ spl-token accounts |
可以看到第 4 行是我們剛剛新發行的代幣,有 100 枚,沒錯。其他是我所持有的其他代幣,與與其對應的持有數量。
輸入以下指令可以看得更清楚我們是在「哪個」帳戶持有「什麼」代幣:
1 | $ spl-token account -v |
執行結果:
1 | $ spl-token account -v |
在觀念說明時說過,NFT 在 Solana 跟一般的 token 其實沒有本質上的區別,只是最小單位、與總發行量都為 1。實作起來會如下:
-- decimals 0
是小數點後有 0 位的意思,所以該代幣只能持有整數,如果嘗試轉 0.1 的話不會噴錯,但帳戶數量不會增加,有興趣可以試試。
1 | $ spl-token create-token --decimals 0 |
執行結果:
1 | $ spl-token create-token --decimals 0 |
接著一樣是要創建對應的帳戶然後鑄造:
1 | $ spl-token create-account 9J7Bmg8Yx4dPsSiiQAvdHuwLS5dCf9ET6jyamwpaJUKR |
注意,這裏其實你也可以 mint 1 個以上,也可以成功,但這樣這個 token 總量就會有 1 個以上,就不是所謂的 NFT 了。
成功 mint 1 個代幣後,我們馬上關閉該代幣的鑄造功能。
這個關閉事不能再打開的,如此就達成意義上的 NFT 了,每個 token 都是獨一無二。
命令:
1 | $ spl-token authorize <代幣 ID> mint --disable |
執行結果:
1 | $ spl-token authorize 9J7Bmg8Yx4dPsSiiQAvdHuwLS5dCf9ET6jyamwpaJUKR mint --disable |
create wallet (key-pair)
1 | // file wallet |
the public key will display on the terminal
if you didn’t save the pubkey, it’s fine.
we can get the pubkey from private-key
1 | solana-keygen pubkey YOUR-PRIVATE-KEY-FILE-PATH |
Verify key-pair
1 | solana-keygen verify PUBKEY PRIVATE-KEY-FILE-PATH |
pubkey
aka. address
aka. wallet address
config
1 | solana config get |
set URL to dev-net for developing
1 | solana config set --url https://api.devnet.solana.com |
send 1 SOL to address
1 | solana airdrop 1 PUBKEY |
get balance of address
1 | solana balance PUBKEY |
transfer
1 | solana transfer --from <KEYPAIR> \ |
1 | // first create a keypair for account address |
1 | solana stake-account <STAKE_ACCOUNT_ADDRESS> |
1 | solana stake-authorize <STAKE_ACCOUNT_ADDRESS> \ |
1 | solana validators |
1 | solana delegate-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <VOTE_ACCOUNT_ADDRESS> \ |
1 | solana deactivate-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> \ |
only work when the stake-account deactived
1 | solana withdraw-stake --withdraw-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <RECIPIENT_ADDRESS> <AMOUNT> \ |
You may want to delegate stake to additional validators while your existing stake is not eligible for withdrawal. It might not be eligible because it is currently staked, cooling down, or locked up. To transfer tokens from an existing stake account to a new one
1 | solana split-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <NEW_STAKE_ACCOUNT_KEYPAIR> <AMOUNT> \ |
找工作時,個人的 GitHub 常常會是一個審核的重點,可以看到這個人有做過哪些專案、code 寫的乾不乾淨、是否有參與什麼貢獻等。而 profile 頁會是別人進來最先會看到的,所以得好好整理才行,好給人好的第一印象!
跟面試一樣,簡短俐落的內容效果最好!除此之外,因應平台屬性不同,調性也可以有所不同。像是在 Linkedin 可以寫得專業點,給人可信任的感覺,因為主要是給 HR 看的;而在 GitHub 則多數是工程師才會進來看,也就是可能的未來同事或合作夥伴,所以可以弄得活潑點,展現個人魅力、或創意,如果能讓人看了有「哇!我會想跟他工作」或「哈哈,這個人好幽默」的感覺,我想就是不錯的 profile 了。
沒有標準答案。但如果完全沒有方向的話,建議以「簡潔、俐落」為目標。可以適時的加點 emoji 可以讓畫面顏色比較豐富、也可以給人不那麼嚴肅的印象。
如果還是不知該如何起手,這邊分享一個別人做好的 GitHub Profile Generator 😂,可以快速的弄出一個版本,之後有想法再慢慢調整。
連結:https://rahuldkjain.github.io/gh-profile-readme-generator/
然後 FB、twitter、個人部落格等連結,我推薦使用 badge,簡潔又美觀!效果如下
也附上我找到線上別人做好的 badge 資源,可以找需要的使用:
https://github.com/Ileriayo/markdown-badges#usage
最後,因為 GitHub 有支援可以上傳 gif,所以如果有想法,放上一張吸睛的動圖會是很讚的選擇~